Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

So, I am supporting three themes in my app, each with different tintColors. I'm using @EnvironmetObject to track changes. However, I can't use it on SceneDelegate.swift file, because the app crashes. Moreover, accentColor is not an option, as it doesn't change alert tintColor. How can I do it?

Here's some code:

SceneDelegate.swift file

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
    }
}

This approach will crash when the app starts, because it can't finde an @EnvironmentObject in its ancestor.

ContentView.swift file

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)
    }
}

This approach won't work for me either because it doesn't change the tintColor of alerts, for example.

Images

This is what I get if I use accentColor

This is what I get if I use accentColor


This is what I want to achieve

This is what I want to achieve

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
692 views
Welcome To Ask or Share your Answers For Others

1 Answer

Update: posted this demo on GitHub - DemoWindowTint

The below demo is created on setting window's tintColor (which is inherited by all subviews) using the approach provided in How to access own window within SwiftUI view?.

In demo I used NavigationView with couple of NavigationLinks and Button showing Alert.

demo

Tested with following

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
    }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...