问题描述
我正在寻找一种更改状态栏的 text 颜色的方法,该颜色允许为每个视图使用不同的文本颜色.
I'm looking for a way to change the text color of the status bar that allows a different text color to be used for each view.
我见过此问题与解答,但这不是我要查找的内容为了.我不是在寻找只允许所有视图使用一种状态栏文本颜色的解决方案.我想为每个视图更改状态栏文本颜色.例如,一个视图可能具有深色背景,因此我需要浅色文本.我可能会导航到具有浅色背景的其他视图,因此现在我需要深色文本.建议的重复答案仅返回.lightContent ,这意味着当我移至其他视图时,状态栏文本颜色无法动态更改.
I've seen this Q&A, but it's not what I'm looking for. I'm not looking for solutions that only allow for one status bar text color for all views. I want to change the status bar text color for each view. For example, one view might have a dark background and so I need light text. I might navigate to another view with a light background, so now I need dark text. The suggested duplicate answer only returns .lightContent, which means that the status bar text color cannot change dynamically when I move to a different view.
此处的答案在我的计算机上有效,但效果不佳.它下面的评论证实了这一点.滞后是不可接受的,因此此解决方案不好.
This answer here works on my machine, but it's not performant. A comment under it corroborates this. The lag is unacceptable, so this solution is not good.
到目前为止,我看到的其他解决方案会导致此特定错误:
Other solutions I've seen so far cause this particular error:
Compiling failed: extensions of generic classes cannot contain '@objc' members
我还尝试在自定义控制器中使用环境对象:
I've also tried using an Environment Object inside my Custom Controller:
import SwiftUI
/// Allows for the status bar colors to be changed from black to white on the dark gray title bar
class Controller<ContentView> : UIHostingController<ContentView> where ContentView : View {
@EnvironmentObject var statusBarTextColor: StatusBarTextColor
lazy var isDark: Bool = self.statusBarTextColor.isDark
override var preferredStatusBarStyle: UIStatusBarStyle {
return isDark ? .lightContent : .darkContent
}
}
这会导致错误:
Thread 1: Fatal error: No ObservableObject of type StatusBarTextColor found. A View.environmentObject(_:) for StatusBarTextColor may be missing as an ancestor of this view.
在我的SceneDelegate文件中,我确实指定了StatusBarTextColor环境对象:
Inside my SceneDelegate file, I do specify the StatusBarTextColor environmentObject:
window.rootViewController = Controller(
rootView: Home()
.environmentObject(PostData())
.environmentObject(CardPosition())
.environmentObject(StatusBarTextColor())
)
这是ObservableObject本身:
And this is the ObservableObject itself:
import Combine
import SwiftUI
final class StatusBarTextColor: ObservableObject {
@Published var isDark: Bool = true
}
如果我想知道为什么这行不通,那是因为Controller在StatusBarTextColor可用之前就已初始化.
If I were to guess why this doesn't work, I'd say it's because the Controller gets initialized before StatusBarTextColor is available.
我对这个问题的研究越多,我就认为没有办法解决.我几乎阅读了有关该主题的每篇文章,答案和视频.他们都使用Controller仅返回.lightContent,或者使用情节提要和多个控制器,这不是我正在使用的.
The more I look into this problem, the more I think there isn't a solution. I've gone through just about every article, answer, and video on the subject. They all either use a Controller to only return .lightContent, or use storyboards and multiple controllers, which isn't what I'm using.
推荐答案
您可以使用找到的解决方案,但是您可以创建一个名为onWillDisappear的视图修饰符,该修饰符公开viewWillDisappear,而不是使用onDisappear(这会延迟颜色更改,直到视图完全消失).颜色更改将尽快发生.
You can use the solution you found here, but instead of using onDisappear, which will have a delay for the color change until the view is completely gone, you can create a view modifier called onWillDisappear that exposes viewWillDisappear. The color change will happen as sooner.
用法:
struct MyClass: View {
@Environment(\.localStatusBarStyle) var statusBarStyle
// ...
SomeView()
}.onAppear {
self.statusBarStyle.currentStyle = .darkContent
}
.onWillDisappear {
self.statusBarStyle.currentStyle = .lightContent
}
}
代码:
import SwiftUI
class HostingController<Content>: UIHostingController<Content> where Content: View {
private var internalStyle = UIStatusBarStyle.lightContent
@objc override dynamic open var preferredStatusBarStyle: UIStatusBarStyle {
get {
internalStyle
}
set {
internalStyle = newValue
self.setNeedsStatusBarAppearanceUpdate()
}
}
override init(rootView: Content) {
super.init(rootView:rootView)
LocalStatusBarStyleKey.defaultValue.getter = { self.preferredStatusBarStyle }
LocalStatusBarStyleKey.defaultValue.setter = { self.preferredStatusBarStyle = $0 }
}
@objc required dynamic init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
class LocalStatusBarStyle { // style proxy to be stored in Environment
fileprivate var getter: () -> UIStatusBarStyle = { .default }
fileprivate var setter: (UIStatusBarStyle) -> Void = {_ in}
var currentStyle: UIStatusBarStyle {
get { self.getter() }
set { self.setter(newValue) }
}
}
// Custom Environment key, as it is set once, it can be accessed from anywhere
// of SwiftUI view hierarchy
struct LocalStatusBarStyleKey: EnvironmentKey {
static let defaultValue: LocalStatusBarStyle = LocalStatusBarStyle()
}
extension EnvironmentValues { // Environment key path variable
var localStatusBarStyle: LocalStatusBarStyle {
get {
return self[LocalStatusBarStyleKey.self]
}
}
}
struct WillDisappearHandler: UIViewControllerRepresentable {
func makeCoordinator() -> WillDisappearHandler.Coordinator {
Coordinator(onWillDisappear: onWillDisappear)
}
let onWillDisappear: () -> Void
func makeUIViewController(context: UIViewControllerRepresentableContext<WillDisappearHandler>) -> UIViewController {
context.coordinator
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<WillDisappearHandler>) {
}
typealias UIViewControllerType = UIViewController
class Coordinator: UIViewController {
let onWillDisappear: () -> Void
init(onWillDisappear: @escaping () -> Void) {
self.onWillDisappear = onWillDisappear
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
onWillDisappear()
}
}
}
struct WillDisappearModifier: ViewModifier {
let callback: () -> Void
func body(content: Content) -> some View {
content
.background(WillDisappearHandler(onWillDisappear: callback))
}
}
extension View {
func onWillDisappear(_ perform: @escaping () -> Void) -> some View {
self.modifier(WillDisappearModifier(callback: perform))
}
}
请参阅带有onWillDisappear代码的原始帖子
See original post with onWillDisappear code here
这篇关于如何在SwiftUI中更改每个视图的状态栏文本颜色?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!