如何在SwiftUI中更改每个视图的状态栏文本颜色? [英] How can I change the status bar text color per view in SwiftUI?

查看:100
本文介绍了如何在SwiftUI中更改每个视图的状态栏文本颜色?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种更改状态栏的 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.

推荐答案

您可以使用找到的解决方案

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中更改每个视图的状态栏文本颜色?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆