SwiftUI 中某些环境自动更新背后的奥秘

Posted

技术标签:

【中文标题】SwiftUI 中某些环境自动更新背后的奥秘【英文标题】:The Mystery behind auto update of some Environment in SwiftUI 【发布时间】:2021-03-29 17:23:50 【问题描述】:

我可以使用环境修改器轻松更改视图级别中名为 backgroundColor 的自定义环境!像这样下来的代码:

CustomView()
  .environment(\.backgroundColor, toggleCustomViewBackgroundColor ? Color.yellow : Color.green)

如您所见,我可以为 CustomView() 更改/更新@Environment(\.backgroundColor) var backgroundColor: Color。而且效果很好!

那么我如何在整个项目中更改/更新@Environment(\.backgroundColor) var backgroundColor: Color

也许你们中的一些人会说这样做:

ContentView()
  .environment(\.backgroundColor, toggleAppBackgroundColor ? Color.yellow : Color.green)

这将是在整个 Project 中更新 @Environment(\.backgroundColor) var backgroundColor: Color 的一种方式,但正如我们现在 colorScheme 那样 以这种方式工作!它会根据设备当前的实际暗/亮模式在整个项目中进行自我更新,而不使用环境修改器!

让我说一下发生了什么! colorScheme 可以在不使用环境修饰符的情况下自行更新,当然它有一个逻辑可以使更新发生在整个项目中,为了让我们的一切变得简单,我制作了一个按钮,它播放一个逻辑,可以在整个项目中更新 @Environment(\.backgroundColor) var backgroundColor: Color 而不使用环境修饰符,所以 如何 colorScheme 可以自我更新,我也想为我的 Custom-Environment 提供该功能。例如,点击该按钮 backgroundColor-Environment 会明白现在是时候在整个项目中更新 backgroundColor 了。每个子视图都会注意到新的更新!比如colorScheme


private struct BackgroundColorKey: EnvironmentKey 
    
    static var defaultValue = Color.yellow
    



extension EnvironmentValues 
    
    var backgroundColor: Color 
        get  return self[BackgroundColorKey.self] 
        set(newValue)  self[BackgroundColorKey.self] = newValue 
    
    


struct CustomView: View 
    
    @Environment(\.backgroundColor) var backgroundColor: Color
    
    var body: some View 
        
        VStack 
            
            Text("Hello world!")
                .background(backgroundColor)
                .padding()
            
        
        
    


import SwiftUI

struct ContentView: View 
    
    @Environment(\.backgroundColor) var backgroundColor: Color
    
    @State private var toggleCustomViewBackgroundColor: Bool = Bool()
    
    var body: some View 
        
        
        Button("Update backgroundColor in App Level!") 
            
            // Update backgroundColor in App Level, witout using environment modifier!!!
        
        .padding()
        
        
        Text("Hello world!")
            .background(backgroundColor)
            .padding()
        
        
        Button("toggle backgroundColor in View Level!") 
            
            toggleCustomViewBackgroundColor.toggle()
        
        .padding()
        
        CustomView()
            .environment(\.backgroundColor, toggleCustomViewBackgroundColor ? Color.yellow : Color.green)
        

    

【问题讨论】:

【参考方案1】:

据我们所知,我的问题是寻找在不使用 环境修饰符的情况下更新自定义环境的答案比如 colorScheme

这就是我认为 ColorScheme Environment 应该发生的事情!默认情况下,Apple 为我们创建的每个 SwiftUI 项目都做了类似这样的代码!但是环境修饰符应用了Undercover! 我们看不到它!我已经证明了这一点!

ContentView()
  .environment(\.colorScheme, colorSchemeUpdater())

我的理论的证明:

如果您尝试在 App 中阅读 colorScheme,它不会更新自己以获得实际正确的值!因为在应用中 environment modifier for colorScheme 没有应用以获得新的更新!现在就自己试试这个代码吧!它不会显示或更新 colorScheme 的真实值!

import SwiftUI

@main
struct EnvironmentApp: App 
    
    @Environment(\.colorScheme) var colorScheme
    
    var body: some Scene 
        WindowGroup 
            
            Text(colorScheme == .dark ? "dark" : "light")
            
            ContentView()     
        
    

但是,如果您尝试使用此代码,它会起作用并且会显示正确的价值!甚至我们也没有在 ContentView() 上为 colorScheme 明确使用 环境修饰符,因为 Apple 为我们完成了它卧底!

struct ContentView: View 
    
    @Environment(\.colorScheme) var colorScheme

    var body: some View 
        
        Text(colorScheme == .dark ? "dark" : "light")
    
    


其他环境也有类似scenePhase、horizo​​ntalSizeClass、verticalSizeClass,都默认应用到WindowGroup

侧的Views

谜团解开!


【讨论】:

以上是关于SwiftUI 中某些环境自动更新背后的奥秘的主要内容,如果未能解决你的问题,请参考以下文章

如何使用@EnvironmentObject 在 SwiftUI 中自动填充和更新列表?

新版Azure Automation Account 浅析 --- 更新Powershell模块和创建Runbook

文智背后的奥秘系列篇——结构化抽取平台

SwiftUI App入口生命周期管理方式(Life Cycle)

SwiftUI iOS 14 |在 HStack 中自动展开文本框和内容

超详细:SwiftUI文本排版布局和动态字体缩放的奥秘