SwiftUI点击FirstView按钮传Bool控制ContentView显示SecondView方法
问题根因
FirstView和ContentView中各自初始化了独立的ShowPicker实例,两个实例内存完全隔离,属性变更无法同步,自然达不到联动效果。
正确实现方式
方案1:父视图持有实例,直接注入子视图(适合层级简单的父子视图场景)
iOS14+ 推荐父视图用@StateObject持有可观察对象,保证实例生命周期和视图绑定,不会随视图重绘被重复创建,再将同一个实例传递给子视图即可。
- 可观察类
ShowPicker无需修改
class ShowPicker: ObservableObject { @Published var pickerIsShow = false }
- 修改
ContentView,持有唯一的状态实例,初始化子视图时传入实例
struct ContentView: View { // 唯一状态实例,由顶层父视图持有 @StateObject private var showPicker = ShowPicker() var body: some View { VStack { // 注入同一个实例给子视图 FirstView(showPicker: showPicker) secondView() .offset(y: self.showPicker.pickerIsShow ? 0 : UIScreen.main.bounds.height) } } }
- 修改
FirstView,删除本地初始化的ShowPicker,改为接收外部传入的实例
struct FirstView: View { // 接收父视图传入的共享实例 @ObservedObject var showPicker: ShowPicker var body: some View { VStack{ Button("showPicker"){ self.showPicker.pickerIsShow.toggle() } } } }
方案2:环境对象注入(适合视图层级深、不想逐层传参的场景)
把状态实例注入到当前视图层级的环境中,所有子层级视图都可以直接从环境获取实例,不需要逐层传递参数。
ShowPicker类保持不变- 修改
ContentView,持有实例后通过.environmentObjectmodifier注入环境
struct ContentView: View { @StateObject private var showPicker = ShowPicker() var body: some View { VStack { // 不需要给FirstView传参 FirstView() secondView() .offset(y: self.showPicker.pickerIsShow ? 0 : UIScreen.main.bounds.height) } // 将实例注入当前视图层级的环境 .environmentObject(showPicker) } }
- 修改
FirstView,通过@EnvironmentObject从环境中获取共享实例
struct FirstView: View { // 直接从环境读取共享实例,不需要传参 @EnvironmentObject private var showPicker: ShowPicker var body: some View { VStack{ Button("showPicker"){ self.showPicker.pickerIsShow.toggle() } } } }
注意事项
- 如果项目部署目标低于iOS14,无法使用
@StateObject,父视图可以改用@ObservedObject持有实例,需要手动保证实例不会随视图重绘被重复创建(比如可以在视图结构体外部初始化实例后传入)。 - 所有需要共享状态的视图,必须访问同一个
ObservableObject实例,才能实现状态同步。
内容的提问来源于stack exchange,提问作者Dmitry
相关产品推荐
相关产品推荐

