当前位置: 首页 > iOS > 正文

SwiftUI数据流和绑定备忘

SwiftUI数据流和绑定备忘

@State,@Binding,@ObservableObject,@EnvironmentObject,@@Environment备忘与实例

1. @State 和 @Binding

@State 修饰当前视图里面的一个状态量,当改变这个状态量后,当前视图自动刷新
@State 修饰的状态量可以传给子视图,这个子视图中接受的属性必须要用@Binding修饰,传递给子视图时,需要用$在参数名前面表示是值传递
下面代码运行时,点击Update State之后,两个Text内容都变成了"State Changed By Son"

 import SwiftUI

struct Me: View {
  @State var myState:String = "Initial State"  //父视图@State修饰 状态量

  var body: some View {
    VStack{
      Text("Parent state: \(myState)")
      Divider()
      MySon(stateFromParent:self.$myState) // 父视图状态量传递给子视图时,用$符修饰
    }  
  }
}

struct MySon:View {
  @Binding var stateFromParent:String  //子视图用@Binding修饰从父视图接收的状态量

  var body: some View {
    VStack {
      Text("Son State:\(stateFromParent)")
      Button("Update State") {
        self.stateFromParent = "State Changed By Son"
      }
    }
  }
}

struct Me_Previews: PreviewProvider {
  static var previews: some View {
    Me()
  }
}

2. ObservableObject,@ObservedObject和@Published

ObservableObject是一个protocol,实现ObservableObject的类中的使用@Published修饰的property会被SwiftUI监听,
一旦@Published修饰的property发生改变,所有关联到这个ObservableObject对象的View都会被自动更新.需要注意的是,
View关联ObservableObject对象的方式是使用@ObservedObject修饰property.@ObservedObject修饰对象可以传递给各个独立的
View,传参时参数名前不需要加$符了,当初正常的引用参数传递.使用ObservableObject,@ObservedObject和@Published可以完全替代@State和@Binding.

下面代码运行时,点击Update State之后,两个Text内容都变成了"State Changed By Son"

import SwiftUI

struct Me: View {
  @ObservedObject var myState:StateHolder = StateHolder(currentState:"State of Me") //@ObservedObject修饰的对象可以被多个独立view使用,不仅仅是子View

  var body: some View {
    VStack{
      Text("Parent state: \(myState.currentState)") //这里myState前面不需要$了
      Divider()
      MySon(stateOfMySon:myState)
    }
  }
}

struct Me_Previews: PreviewProvider {
  static var previews: some View {
    Me()
  }
}

struct MySon:View {
  @ObservedObject var stateOfMySon:StateHolder

  var body: some View {
    VStack {
      Text("Son State:\(stateOfMySon.currentState)")
      Button("Update State") {
        self.stateOfMySon.currentState = "State Changed By Son"  //改变这个属性,会更新所有关联到stateOfMySon(其实和Me的myState是一个对象,同一个引用)的View
      }
    }
  }
}

class StateHolder:ObservableObject {
  @Published var currentState:String

  init(currentState:String) {
    self.currentState = currentState
  }
}

3. @EnvironmentObject

@EnvironmentObject同样使用ObservableObject和@Published机制.@EnvironmentObject修饰的属性相当于从全局环境中拿数据.通过它,
我们可以避免在初始 View 时创建 ObservableObject, 而是从环境中获取 ObservableObject.这个环境是当前视图的父视图的环境.
在创建父视图时,使用.environmentObject(envObj)来设置环境参数.

同一个上下文只会存在一个类型相同的@EnvironmentObject对象,当存在多个时,子View设置的environmentObject会覆盖掉父View的相同类型的对象.
默认View中取离自己最近的父View设置的EnvironmentObject.

import SwiftUI

/**
 下面例子中,A包含B,B包含C,A,B,C都有一个@EnvironmentObject currentState
 首先通过VStack设置了全局的环境变量Env_Global,创建B()时重设了子环境变量Env_B,Env_B就覆盖了Env_Global
 于是
 A()和C()中显示state of env:Env_Global
 B()中显示state of env:Env_B
 */
struct Me: View {
  var body: some View {
    List {
      A()

      B().environmentObject(StateHolder(currentState:"Env_B"))

      C()
    }.environmentObject(StateHolder(currentState:"Env_Global"))
    .font(.system(size:20,weight:.light))
    .padding(4)
  }
}

struct Me_Previews: PreviewProvider {
  static var previews: some View {
    Me()
  }
}

class StateHolder:ObservableObject {
  @Published var currentState:String

  init(currentState:String) {
    self.currentState = currentState
  }
}

struct A: View {
  @EnvironmentObject var currentState:StateHolder

  var body: some View {
    VStack {
      Text("This is A")

      Text("state of env:\(currentState.currentState)")

      B()
    }
  }
}

struct B: View {
  @EnvironmentObject var currentState:StateHolder
  var body: some View {
    VStack {
      Text("This is B")
      Text("state of env:\(currentState.currentState)")
      C()
    }
  }
}

struct C: View {
  @EnvironmentObject var currentState:StateHolder
  var body: some View {
    VStack {
      Text("This is C")
      Text("state of env:\(currentState.currentState)")
    }
  }
}

4. @Environment

SwiftUI 本身就有很多系统级别的设定,通过 @Environment 来获取到它们.
下面代码显示zh_CN

import SwiftUI

struct Me: View {
  /**
   @Environment注解参数为key
   */
  @Environment(\.calendar) var calendar: Calendar
  @Environment(\.locale) var locale: Locale
  @Environment(\.colorScheme) var colorScheme: ColorScheme

  var body: some View {
    return Text(locale.identifier)
  }
}

struct Me_Previews: PreviewProvider {
  static var previews: some View {
    Me()
  }
}
赞 赏

   微信赞赏  支付宝赞赏


本文固定链接: https://www.jack-yin.com/coding/ios/3151.html | 边城网事

该日志由 边城网事 于2020年05月27日发表在 iOS 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: SwiftUI数据流和绑定备忘 | 边城网事
关键字: , ,

SwiftUI数据流和绑定备忘 暂无评论

发表评论

快捷键:Ctrl+Enter