如何更改整个应用程序的tintColor?SwiftUI

4
所以,我的应用程序支持三个主题,每个主题具有不同的tintColors。我正在使用@EnvironmetObject跟踪更改。但是,我不能在SceneDelegate.swift文件中使用它,因为应用程序会崩溃。此外,accentColor不是一种选择,因为它不会改变警报tintColor。我该怎么做?
下面是一些代码:
SceneDelegate.swift 文件
class SceneDelegate: UIResponder, UIWindowSceneDelegate {

@EnvironmentObject var userData: UserData

var window: UIWindow?

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).

    // Create the SwiftUI view that provides the window contents.
    let contentView = TasksView()

    // Use a UIHostingController as window root view controller.
    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = UIHostingController(rootView: contentView.environmentObject(UserData()))
        self.window = window
        window.makeKeyAndVisible()

        window.tintColor = userData.selectedTheme.tintColor
    }
}

这种方法会在应用启动时崩溃,因为它无法在其祖先中找到 @EnvironmentObject。

ContentView.swift 文件

struct ContentView: View {

    @EnvironmentObject var userData: UserData

    var body: some View {
        NavigationView{
            List(userData.tasks) { task in
                TaskRow(taskTitle: task.title, taskDetail: task.detail)
            }
            .navigationBarTitle(Text("Tasks"), displayMode: .automatic)

            .navigationBarItems(
                leading: NavigationLink(destination: SettingsView(), label: {
                    Image(systemName: "gear").imageScale(.large)
                }),
                trailing: NavigationLink(destination: AddTaskView(), label: {
                    Image(systemName: "plus").imageScale(.large)
                })
            )
        }.navigationViewStyle(StackNavigationViewStyle())
         .accentColor(userData.selectedTheme.accentColor)
    }
}

这种方法对我也不可行,因为它无法改变警报的“tintColor”(例如)。

图片

如果我使用accentColor,我就会得到这个结果

如果我使用accentColor,我就会得到这个结果


这是我想要实现的效果

这是我想要实现的效果


1
你能提供更多的上下文吗?比如展示一下你试图放在SceneDelegate中的代码,以及你所说的它不改变警告色调是什么意思? - Glenn Posadas
嘿 @Glenn,我刚刚添加了你要求的内容。你现在有机会知道如何做吗? - Alejo Flores
我已经尝试了所有的方法。我认为你无法对其进行任何操作。设置UIButton.appearance()也不起作用。Alert.Button是一个结构体,不应该被子类化,它也不是一个View,你无法更改它的颜色属性。 - Glenn Posadas
UIView.appearance().tintColor = .green 将使 SwiftUI 警告框中的按钮变为绿色。 - Mike Taverne
3个回答

4

在你的 Assets.xcassets 文件中应该有一个名为 AccentColor 的条目。点击这个条目,选择 Universal 矩形。然后你可以在右侧的属性检查器中设置任何颜色。

这将设置所有视图的颜色,甚至适用于模态视图,如果您尝试手动覆盖它们,可能会表现得有点奇怪。

Xcode 截图


这应该是被接受的答案,至少对于SwiftUI 2.0和SwiftUI 3.0。谢谢! - Juan Manuel Gentili
它在模态框等方面表现非常出色,但如果我这样做,用户如何自定义他们想要的颜色? - user2619824
一种方法是将颜色值保存在例如@Published变量中,并将此值作为.accentColor(yourColorVar)传递给您的内容视图。我不知道是否有任何副作用或者这是否是首选的方法,但这是我想到的第一件事。 - tomaculum

1
你可以通过调用来实现它。
UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = .red

SceneDelegatewillConnectTo方法中。

1

更新:在 GitHub 上发布了此演示 - DemoWindowTint

下面的演示是基于使用如何在 SwiftUI 视图中访问自己的窗口?提供的方法设置窗口的tintColor(该颜色会被所有子视图继承)。

在演示中,我使用了NavigationView,并添加了几个NavigationLinksButton来显示Alert

demo

测试所用的内容如下:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?


    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)

            let contentView = ContentView()
                .environment(\.hostingWindow, { [weak window] in
                    return window })

            window.rootViewController = UIHostingController(rootView: contentView)

            self.window = window
    ...

struct ContentView: View {
    @Environment(\.hostingWindow) var hostingWindow
   ... // body can be any

    .onAppear {
            // can be loaded from UserDefaults here, and later changed on any action
            self.hostingWindow()?.tintColor = UIColor.red
    }

嗨 @Asperi 。我无法使其工作!你能否也请发布你的 SceneDelegate 文件? - Alejo Flores
@AlejoFlores,已更新。您需要从提供的链接中复制与“hostingWindow”相关的所有内容。 - Asperi
不,我的真实项目中也使用了环境对象。 - Asperi
@AlejoFlores,具体是什么不起作用?在onAppear中,hostingWindow是否为非nil值? - Asperi
让我们在聊天中继续这个讨论 - Asperi
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接