SwiftUI 入门教程 – 用户交互状态管理

在 SwiftUI 中,视图的状态管理分为两种:一种是只读的数据,称之为 Swift 的属性(Property);一种则是可读可写的,需要使用 State 进行数据绑定。子视图的状态管理都存在最近的公共祖先视图上,如下图:

image.png

当使用 State 进行绑定之后,当数据源发生改变的时候,SwiftUI 会自动去更新需要改变的视图。

使用 Swift 的属性来存储不变的数据

使用属性来存储一些不变的数据,比如视频的标题:

struct ContentView: View {

    let videoTitle = "视频标题"
    
    var body: some View {
        Text(videoTitle)
    }
}

首先,声明一个 videoTitle 属性来存储视频标题,然后在 Text 中展示标题内容。

State 的使用

当视图的某个数据需要改变时,使用 State 的属性包裹器声明即可。比如播放按钮,需要根据播放的状态来改变按钮的图标。我们可以声明一个 isPlaying 的属性来标明是否正在播放:

struct ContentView: View {

    @State private var isPlaying = false
    var body: some View {
        Button(action: {
            self.isPlaying.toggle()
        }) {
            Image(systemName: isPlaying ? "pause.circle" : "play.circle")
        }
    }
}

首先,我们声明一个用 @State 修饰的布尔类型的属性 isPlaying。接着,在 body 中返回一个 Button。Button 的 action 则是调用一个 toggle() 函数。它的作用是将 true 变为 false,或者将 false 变为 true。最后,则是根据 isPlaying 的值来决定按钮的图标是播放还是暂定。

当我们将 isPlaying 用 State 包裹时,就相当于告诉 SwiftUI 它需要管理底层存储的数据。 Button 通过 state 的 wrappedValue 属性去读写存储的数据。当你修改了 isPlaying 的值,SwiftUI 则会去更新 Image 视图。

关于 wrappedValue:通过底层代码可以看到,State 是一个结构体。而 wrappedValue 则是它的一个属性,从名字也可以看出是用来存储底层的数据。通常,开发者不需要显式的去调用它,直接访问 State 包裹的属性即可正常的访问底层存储的数据。

需要注意的是,声明 State 属性的时候,应该加上 private 修饰符,这样可以保证属性的生命周期与相应的视图生命周期保持一致。所以,对于持久化存储的数据不要使用 State,因为这样会导致数据的生命周期长过视图的生命周期。State 应该用于保存视图的用户交互相关的数据,比如按钮的高亮状态,过滤设置等。

通过 Bind 共享数据

如果我们想让子视图也可以访问 State 存储的数据,可以通过 @Bind 来实现。比如下面的代码:

// 播放按钮
struct PlayButton: View {
    @Binding var isPlaying: Bool
    
    var body: some View {
        Button(action: {
            self.isPlaying.toggle()
        }) {
            Image(systemName: isPlaying ? "pause.circle" : "play.circle")
        }
    }
}
// 播放视图
struct PlayerView: View {
    @State private var isPlaying: Bool = false
    var body: some View {
        PlayButton(isPlaying: $isPlaying)
    }
}

PlayButton_Previews 如果默认代码会报错,在里面声明一个 State 属性即可:

struct PlayButton_Previews: PreviewProvider {
    @State static var value = false
    static var previews: some View {
        PlayButton(isPlaying: $value)
    }
}

$ 前缀会去读取 projectedValue 的值,它是 Bind 底层存储数据的属性。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYm9tbLh' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片