Swiftui:在环境对象中使用Colorscheme

发布于 2025-01-25 20:29:30 字数 3143 浏览 2 评论 0 原文

在我们的应用中,我们有一个基本的调色板用于主要设计,但是用户也有可能通过管理系统选择自己的颜色(用于白色标签目的)。这些颜色作为十六进制字符串返回给我们,并使用以下模型存储在 BusinessProfile 对象中:

struct BusinessProfileColors: Codable {
    let success: BusinessProfileColor?
    let warning: BusinessProfileColor?
    let highlight: BusinessProfileColor?
    // ... more colours here
}

struct BusinessProfileColor: Codable {
    let light: String?
    let dark: String?
}

因此,我正在尝试创建一个类,该类将检查>中是否存在有效的Hex颜色的存在。 BusinessProfile 并使用这些(根据App State选择正确的轻/深色模式颜色)。如果特定调色板的颜色值为 nil 或不是有效的十六进制字符串,我们将落在标准设计颜色上。这是班级的外观:

class ColorPalette: ObservableObject {
    @Environment(\.colorScheme) var colorScheme
    let container: DIContainer
    
    init(container: DIContainer) {
        self.container = container
    }
    
    private func dynamicColor(lightColor: Color?, darkColor: Color?, defaultColor: Color) -> Color {
        switch colorScheme {
        case .dark:
            return darkColor ?? lightColor ?? defaultColor
        default:
            return lightColor ?? defaultColor
        }
    }
    
    var alertSuccess: Color {
        return dynamicColor(
            lightColor: Color(hex: container.appState.value.businessData.businessProfile?.colors?.success?.light),
            darkColor: Color(hex: container.appState.value.businessData.businessProfile?.colors?.success?.dark),
            defaultColor: Color("Success"))
    }

    // More colours follow the same pattern
}

想法是,我想将其作为 @environmentObject 这样的视图将其传递给我的观点:

@EnvironmentObject var colorPalette: DynamicColors

这样我就可以在这些视图中声明我想要的颜色,例如

text
.foregroundColor(colorPalette.alertSuccess)

:我在我的第一个父视图( rootview.swift )中声明此类的实例为 @StateObject var 如下:

@StateObject var colorpalette:dynamicColors

因此,当我首次初始化rootview时,它就是这样:(

RootView(viewModel: RootViewModel(container: viewModel.environment.container), colorPalette: .init(container: viewModel.environment.container))
            

nb: viewModel.environemnt.container 是我们存储 business> businessProfile )。

然后,我将其作为环境对象从rootview到我需要这样的颜色的第一个视图:

TabBarView(viewModel: .init(container: viewModel.container))
                .environmentObject(colorPalette)

但是,在 tabbarview 中,api结果的颜色正在返回和显示,光/暗模式开关无济于事。仅显示光模式颜色。

如果我更改设置,以便在每个视图上单独声明 colorpalette ,然后从这里传递 colorscheme 都可以正常工作,例如:

struct SomeView: View {
    @Environment(\.colorScheme) var colorScheme
    let container: DIContainer
    
    var colorPalette: ColorPalette {
      ColorPalette(colorScheme: colorScheme, container: container) // Pass in the color scheme from the current view and use this in the ColorPalette class
    }
}

但是,这似乎是非常沉重的手。我宁愿使用 @environmentObject ,因为它似乎非常适合这种情况。但是,我如何利用 @environment(\。colorscheme)在这种情况下从我的 colorpalette 类中。

In our app, we have a basic colour palette used for the main design, however there is also the possibility for the user to choose their own colours via an admin system (for white labelling purposes). These colours are returned to us as hex strings and stored in a BusinessProfile object using the following model:

struct BusinessProfileColors: Codable {
    let success: BusinessProfileColor?
    let warning: BusinessProfileColor?
    let highlight: BusinessProfileColor?
    // ... more colours here
}

struct BusinessProfileColor: Codable {
    let light: String?
    let dark: String?
}

So I am trying to create a class which will check for the presence of valid hex colours in the BusinessProfile and use these (with the correct light/dark mode colours selected according to the app state). If the colour value for a specific palette is nil or not a valid hex string, we will fall back on the standard design colours. Here is how the class looks:

class ColorPalette: ObservableObject {
    @Environment(\.colorScheme) var colorScheme
    let container: DIContainer
    
    init(container: DIContainer) {
        self.container = container
    }
    
    private func dynamicColor(lightColor: Color?, darkColor: Color?, defaultColor: Color) -> Color {
        switch colorScheme {
        case .dark:
            return darkColor ?? lightColor ?? defaultColor
        default:
            return lightColor ?? defaultColor
        }
    }
    
    var alertSuccess: Color {
        return dynamicColor(
            lightColor: Color(hex: container.appState.value.businessData.businessProfile?.colors?.success?.light),
            darkColor: Color(hex: container.appState.value.businessData.businessProfile?.colors?.success?.dark),
            defaultColor: Color("Success"))
    }

    // More colours follow the same pattern
}

The idea is that I want to pass this to my views as an @EnvironmentObject like this:

@EnvironmentObject var colorPalette: DynamicColors

So that within these views I can declare the colours I want simply like e.g.:

text
.foregroundColor(colorPalette.alertSuccess)

So I am declaring an instance of this class in my first parent view (RootView.swift) as an @StateObject var as follows:

@StateObject var colorPalette: DynamicColors

So when I first initialise RootView it is like this:

RootView(viewModel: RootViewModel(container: viewModel.environment.container), colorPalette: .init(container: viewModel.environment.container))
            

(NB: the viewModel.environemnt.container is where we store the BusinessProfile).

Then I am passing this as an environment object from the RootView to the first view where I need the colours like this:

TabBarView(viewModel: .init(container: viewModel.container))
                .environmentObject(colorPalette)

However, in TabBarView, whilst the colours from the API results are returning and being displayed, the light/dark mode switch does nothing. Only the light mode colours are showing.

If I change the setup so that I declare the ColorPalette individually on each view and pass in the colorScheme from here all works fine, e.g.:

struct SomeView: View {
    @Environment(\.colorScheme) var colorScheme
    let container: DIContainer
    
    var colorPalette: ColorPalette {
      ColorPalette(colorScheme: colorScheme, container: container) // Pass in the color scheme from the current view and use this in the ColorPalette class
    }
}

However, this seems extremely heavy handed and I would much rather use @EnvironmentObject as it seems well suited to this scenario. However, how can I leverage the @Environment(\.colorScheme) property in this scenario from within my ColorPalette class?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文