问题
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 want to achieve
回答1:
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
.
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
}
来源:https://stackoverflow.com/questions/60368765/how-to-change-tintcolor-of-whole-app-swiftui