一 @State
加了@State注解的變量,視圖通過監(jiān)視和讀取該變量來重新渲染UI缺虐。
struct NextPageView: View {
// State針對具體View的內(nèi)部變量進行管理,不應(yīng)該從外部被允許訪問礁凡,所以應(yīng)該標記為private
@State private var count:Int = 0;
@State private var name:String = "";
var body: some View {
VStack{
Text("數(shù)量 = \(count)")
Button("數(shù)量+1"){
count = count+1
}
// 只讀直接使用變量名即可
Text("你的名字 = \(name)")
// 如果是讀寫都有高氮,引用屬性需要$開頭
TextField("請輸入你的名字", text: $name)
}
}
}
二 @Published
@Published是SwiftUI最有用的包裝之一慧妄,允許我們創(chuàng)建出能夠被自動觀察的對象屬性,SwiftUI會自動監(jiān)視這個屬性剪芍,一旦發(fā)生了改變塞淹,會自動修改與該屬性綁定的界面。
三 @ObservedObject
@ObservedObject告訴SwiftUI罪裹,這個對象是可以被觀察的饱普,里面含有被@Published包裝了的屬性。
@ObservedObject包裝的對象状共,必須遵循ObservableObject協(xié)議套耕。也就是說必須是class對象,不能是struct峡继。
@ObservedObject允許外部進行訪問和修改冯袍。
class DataViewModel: ObservableObject {
@Published var value: Int = 0
init() {
for i in 1...10 {
DispatchQueue.main.asyncAfter(deadline: .now() + Double(i)) {
self.value += 1
}
}
}
}
struct NextPageView: View {
@ObservedObject var viewModel = DataViewModel()
var param:String
var body: some View {
VStack{
// viewModel的數(shù)據(jù)變化將自動更新view
Text("數(shù)量 = \(viewModel.value)")
Spacer()
}
}
}
四 @EnvironmentObject
@State
處理單個視圖的局部狀態(tài),以及@ObservedObject
如何使我們在視圖之間傳遞一個對象碾牌,以便我們可以共享它康愤,@ EnvironmentObject
更進一步:我們可以將對象放置到環(huán)境中,以便任何子視圖都可以自動訪問它舶吗。
@EnvironmentObject包裝的屬性是全局的翘瓮,整個app都可以訪問
class User: ObservableObject {
@Published var name = "Sunny"
}
struct EnvironmentObjectView: View {
let user = User()
var body: some View {
VStack {
EditView().environmentObject(user)
DisplayView().environmentObject(user)
}
}
}
struct EditView: View {
@EnvironmentObject var user: User
var body: some View {
TextField("Name", text: $user.name)
}
}
struct DisplayView: View {
@EnvironmentObject var user: User
var body: some View {
Text(user.name)
}
}
五 @Environment
@Environment與@EnvironmentObject作用是不同的,@Environment是從環(huán)境中取出預(yù)定義的值裤翩,比如獲得當(dāng)前是暗黑模式還是正常模式资盅,屏幕的大小等等。
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@Environment(\.managedObjectContext) var managedObjectContext
根據(jù) Light 和 Dark 兩種系統(tǒng)顏色模式來調(diào)整 app 界面的配色是很常見的需求踊赠。方法很簡單呵扛,通過 Environment.colorScheme 獲取當(dāng)前系統(tǒng)環(huán)境的顏色方案就行了:
struct ContentView: View {
// colorScheme values: .light, .dark
@Enviroment(\.colorScheme) var colorScheme
var body: some View {
Text("Hello, World")
.foregroundColor(colorScheme = .light ? .yellow : .blue)
}
}
六 @Binding
把一個視圖的屬性傳至子節(jié)點中,但是又不能直接的傳遞給子節(jié)點筐带,因為在 Swift 中值的傳遞形式是值類型傳遞方式今穿,也就是傳遞給子節(jié)點的是一個拷貝過的值。但是通過 @Binding 修飾器修飾后伦籍,屬性變成了一個引用類型蓝晒,傳遞變成了引用傳遞,這樣父子視圖的狀態(tài)就能關(guān)聯(lián)起來了.
struct NextPageView: View {
// State針對具體View的內(nèi)部變量進行管理帖鸦,不應(yīng)該從外部被允許訪問芝薇,所以應(yīng)該標記為private
@State private var count:Int = 0;
@State private var name:String = "";
var param:String
var body: some View {
VStack{
Text("數(shù)量 = \(count)")
Button("數(shù)量+1"){
count = count+1
}
// 只讀直接使用變量名即可
Text("你的名字 = \(name)")
// 如果是讀寫都有,引用屬性需要$開頭
TextField("請輸入你的名字", text: $name)
// 子節(jié)點傳遞
ChildView(name: $name)
Spacer()
}
}
}
struct ChildView: View {
// 通過@Binding子節(jié)點的修改,會變更到父節(jié)點上
@Binding var name: String
// @State var name: String
var body: some View {
VStack{
Text("子節(jié)點獲取名字 : \(name)")
TextField("子節(jié)點請輸入你的名字", text: $name)
}
}
}
七 @GestureState
@GestureState能夠讓我們傳遞手勢的狀態(tài)作儿,雖然使用@State也能實現(xiàn)洛二,但@GestureState能讓手勢結(jié)束后我們回到最初的狀態(tài)。
struct GesturesUIView: View {
@GestureState var isLongPressed = false
var body: some View {
let longPress = LongPressGesture()
.updating($isLongPressed) { value,state,transcation in
print(value)
state = value
}
return Rectangle()
.fill(isLongPressed ? Color.red: Color.green)
.frame(width: 300, height: 300)
.cornerRadius(8)
.padding()
.scaleEffect(isLongPressed ? 1.2 : 1)
.gesture(longPress)
.animation(.interactiveSpring())
}
}
參考: