如何更改 SwiftUI 应用程序生命周期中的 StatusBarStyle?
How to change StatusBarStyle on SwiftUI App Lifecycle?
我已经花了很多时间试图找到一种使用新生命周期 SwiftUI App[= 将 statusBarStyle 更改为 light/dark 的方法44=].
最新帖子教状态栏怎么隐藏,我不想做,改成深色或浅色就可以了
要改颜色,我最近找到的方法是打开SceneDelegate.swift然后改window.rootViewController使用我自己的 HostingController,但它只适用于使用 UIKit App Delegate Lifecycle 的项目。使用SwiftUI App Lifecycle,不会生成SceneDelegate.swift,请问哪里可以生成?
我可以通过Xcode界面的通用设置来完成。我的问题是关于如何通过代码动态地做到这一点。
- 目标:iOS14
- IDE: Xcode 12 测试版 3
- OS:MacOS 11 大苏尔
以下是我目前得到的。
Everything.swift
import Foundation
import SwiftUI
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) }
}
}
struct LocalStatusBarStyleKey: EnvironmentKey {
static let defaultValue: LocalStatusBarStyle = LocalStatusBarStyle()
}
extension EnvironmentValues { // Environment key path variable
var localStatusBarStyle: LocalStatusBarStyle {
get {
return self[LocalStatusBarStyleKey.self]
}
}
}
class MyHostingController<Content>: UIHostingController<Content> where Content:View {
private var internalStyle = UIStatusBarStyle.default
@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 = [=10=] }
}
@objc required dynamic init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
struct TitlePage: View {
@Environment(\.localStatusBarStyle) var statusBarStyle
@State var title: String
var body: some View {
Text(title).onTapGesture {
if self.statusBarStyle.currentStyle == .darkContent {
self.statusBarStyle.currentStyle = .default
self.title = "isDefault"
} else {
self.statusBarStyle.currentStyle = .darkContent
self.title = "isDark"
}
}
}
}
struct ContainerView: View {
var controllers: [MyHostingController<TitlePage>]
init(_ titles: [String]) {
self.controllers = titles.map { MyHostingController(rootView: TitlePage(title: [=10=])) }
}
var body: some View {
PageViewController(controllers: self.controllers)
}
}
struct PageViewController: UIViewControllerRepresentable {
var controllers: [UIViewController]
func makeUIViewController(context: Context) -> UIPageViewController {
let pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)
return pageViewController
}
func updateUIViewController(_ uiViewController: UIPageViewController, context: Context) {
uiViewController.setViewControllers([controllers[0]], direction: .forward, animated: true)
}
typealias UIViewControllerType = UIPageViewController
}
MyApp.swift
import SwiftUI
@main
struct TestAppApp: App {
var body: some Scene {
WindowGroup {
ContainerView(["Subscribe", "Comment"])
}
}
}
struct TestAppApp_Previews: PreviewProvider {
static var previews: some View {
Text("Hello, World!")
}
}
以前,SceneDelegate
(代码取自 )
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
...
window.rootViewController = MyHostingController(rootView: contentView)
}
之后,没有SceneDelegate
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
MyHostingController(rootView: ContentView())
}
}
}
如果您遵循上面 link 的答案并在此处应用 @main
,您应该能够实现您的更改。
我的建议是您只需创建一个 AppDelegate 适配器并从那里进行您需要的任何自定义。 SwiftUI 将处理 AppDelegate 的创建并管理其生命周期。
创建 AppDelegate class:
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
UIApplication.shared.statusBarStyle = .darkContent
return true
}
}
现在在您的应用程序中:
@main
struct myNewApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
Text("I am a New View")
}
}
}
这并不是一个真正的解决方案,但我能想到(并最终做到)的最好办法是强制应用程序进入暗模式。在 Info.plist 或 NavigationView { ... }.preferredColorScheme(.dark)
这也会更改状态栏。不过,您将无法更改每个视图的状态栏样式。
向 Info.plist 添加两个值:
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
这适用于新的 SwiftUI 应用程序生命周期 (@main)。在 iOS14.4.
上验证
我已经花了很多时间试图找到一种使用新生命周期 SwiftUI App[= 将 statusBarStyle 更改为 light/dark 的方法44=].
最新帖子教状态栏怎么隐藏,我不想做,改成深色或浅色就可以了
要改颜色,我最近找到的方法是打开SceneDelegate.swift然后改window.rootViewController使用我自己的 HostingController,但它只适用于使用 UIKit App Delegate Lifecycle 的项目。使用SwiftUI App Lifecycle,不会生成SceneDelegate.swift,请问哪里可以生成?
我可以通过Xcode界面的通用设置来完成。我的问题是关于如何通过代码动态地做到这一点。
- 目标:iOS14
- IDE: Xcode 12 测试版 3
- OS:MacOS 11 大苏尔
以下是我目前得到的。
Everything.swift
import Foundation
import SwiftUI
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) }
}
}
struct LocalStatusBarStyleKey: EnvironmentKey {
static let defaultValue: LocalStatusBarStyle = LocalStatusBarStyle()
}
extension EnvironmentValues { // Environment key path variable
var localStatusBarStyle: LocalStatusBarStyle {
get {
return self[LocalStatusBarStyleKey.self]
}
}
}
class MyHostingController<Content>: UIHostingController<Content> where Content:View {
private var internalStyle = UIStatusBarStyle.default
@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 = [=10=] }
}
@objc required dynamic init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
struct TitlePage: View {
@Environment(\.localStatusBarStyle) var statusBarStyle
@State var title: String
var body: some View {
Text(title).onTapGesture {
if self.statusBarStyle.currentStyle == .darkContent {
self.statusBarStyle.currentStyle = .default
self.title = "isDefault"
} else {
self.statusBarStyle.currentStyle = .darkContent
self.title = "isDark"
}
}
}
}
struct ContainerView: View {
var controllers: [MyHostingController<TitlePage>]
init(_ titles: [String]) {
self.controllers = titles.map { MyHostingController(rootView: TitlePage(title: [=10=])) }
}
var body: some View {
PageViewController(controllers: self.controllers)
}
}
struct PageViewController: UIViewControllerRepresentable {
var controllers: [UIViewController]
func makeUIViewController(context: Context) -> UIPageViewController {
let pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)
return pageViewController
}
func updateUIViewController(_ uiViewController: UIPageViewController, context: Context) {
uiViewController.setViewControllers([controllers[0]], direction: .forward, animated: true)
}
typealias UIViewControllerType = UIPageViewController
}
MyApp.swift
import SwiftUI
@main
struct TestAppApp: App {
var body: some Scene {
WindowGroup {
ContainerView(["Subscribe", "Comment"])
}
}
}
struct TestAppApp_Previews: PreviewProvider {
static var previews: some View {
Text("Hello, World!")
}
}
以前,SceneDelegate
(代码取自
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
...
window.rootViewController = MyHostingController(rootView: contentView)
}
之后,没有SceneDelegate
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
MyHostingController(rootView: ContentView())
}
}
}
如果您遵循上面 link 的答案并在此处应用 @main
,您应该能够实现您的更改。
我的建议是您只需创建一个 AppDelegate 适配器并从那里进行您需要的任何自定义。 SwiftUI 将处理 AppDelegate 的创建并管理其生命周期。
创建 AppDelegate class:
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
UIApplication.shared.statusBarStyle = .darkContent
return true
}
}
现在在您的应用程序中:
@main
struct myNewApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
Text("I am a New View")
}
}
}
这并不是一个真正的解决方案,但我能想到(并最终做到)的最好办法是强制应用程序进入暗模式。在 Info.plist 或 NavigationView { ... }.preferredColorScheme(.dark)
这也会更改状态栏。不过,您将无法更改每个视图的状态栏样式。
向 Info.plist 添加两个值:
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
这适用于新的 SwiftUI 应用程序生命周期 (@main)。在 iOS14.4.
上验证