SwiftUI提供的属性包装器有 @State,@Binding,@ObservedObject,@EnvironmentObject和@Environment 。
一、@State
@State 是属性包装,我们可以用它来描述View的状态。SwiftUI会将其存储在View结构之外的特殊内部存储器中。只有相关的视图可以访问它。@State 属性的值更改后,SwiftUI就会立即重建View以尊重状态更改。
struct ProductsView: View {
let products: [Product]
@State private var showFavorited: Bool = false
var body: some View {
List {
Button(
action: { self.showFavorited.toggle() },
label: { Text("Change filter") }
)
ForEach(products) { product in
if !self.showFavorited || product.isFavorited {
Text(product.title)
}
}
}
}
}
二、@Binding
必须绑定值类型
@Binding 为值类型提供类似引用的访问。使用 ,它将传递值的副本而不是传递可绑定的引用。
struct FilterView: View {
@Binding var showFavorited: Bool
var body: some View {
Toggle(isOn: $showFavorited) {
Text("Change filter")
}
}
}
struct ProductsView: View {
let products: [Product]
@State private var showFavorited: Bool = false
var body: some View {
List {
FilterView(showFavorited: $showFavorited)
ForEach(products) { product in
if !self.showFavorited || product.isFavorited {
Text(product.title)
}
}
}
}
}
FilterView可以读取和写入ProductsView的showFavorited属性的值。一旦FilterView更改showFavorited属性的值,SwiftUI将重新创建ProductsView和FilterView作为其子级。
三、@ObservedObject
该包装器使我们能够观察SwiftUI框架之外的数据模型中的变化。例如业务逻辑,我们可以在多个独立的视图之间共享它,这些视图可以订阅并观察该对象的更改,并且一旦出现更改,SwiftUI就会重建绑定到该对象的所有视图
SwiftUI在@Published属性包装器的帮助下跟踪ObservableObject的更改,并且一旦标记为@Published更改的属性,SwiftUI就会重建绑定到该对象的所有View。在这里,我们使用@ObservedObject 属性包装器将View绑定到ObservableObject类
import Combine
final class PodcastPlayer: ObservableObject {
@Published private(set) var isPlaying: Bool = false
func play() {
isPlaying = true
}
func pause() {
isPlaying = false
}
}
struct EpisodesView: View {
@ObservedObject var player: PodcastPlayer
...
}
ObservableObject可以在多个视图中共享,所以它必须是 引用类型 或者是 类
四、@EnvironmentObject
无需通过View的init方法传递ObservableObject,而是可以将其隐式注入到View层次结构的Environment中。通过这样做,我们为当前Environment的所有子视图访问此ObservableObject创造了机会。
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let window = UIWindow(frame: UIScreen.main.bounds)
let episodes = [
Episode(id: 1, title: "First episode"),
Episode(id: 2, title: "Second episode")
]
let player = PodcastPlayer()
window.rootViewController = UIHostingController(
rootView: EpisodesView(episodes: episodes)
.environmentObject(player) // 通过environmentObject传递ObservableObject
)
self.window = window
window.makeKeyAndVisible()
}
}
struct EpisodesView: View {
@EnvironmentObject var player: PodcastPlayer // 通过使用@EnvironmentObject定义 来轻松访问
...
}
@EnvironmentObject使用动态成员查找功能在环境中查找ObservableObject的类实例,所以不需要通过View的init方法传递它
五、@Environment
SwiftUI 有一个环境填充了系统范围的设置。我们可以使用@Environment 轻松访问它们。
struct CalendarView: View {
@Environment(\.calendar) var calendar: Calendar
@Environment(\.locale) var locale: Locale
@Environment(\.colorScheme) var colorScheme: ColorScheme
var body: some View {
return Text(locale.identifier)
}
}
通过使用@Environment Property Wrapper标记我们的属性,我们可以访问并订阅系统范围设置的更改。
网友评论