SwiftUI关闭sheet后如何更新前序视图?三层视图间事件怎么传递?
实现方案
三种方案各有适用场景,仅需要单次事件通知优先选方案1,需要同步状态选方案2,层级复杂多组件共享选方案3。
方案1:闭包回调(最轻量化,适合当前简单场景)
逐层传递点击回调闭包,不需要额外管理状态,实现成本最低:
struct FirstView: View { @State var openSecondView: Bool = false var body: some View { Button { openSecondView = true } label: { Text("Click here to show second view") }.sheet(isPresented: $openSecondView) { SecondView( bindSecondView: $openSecondView, onThirdViewButtonClick: { // 这里就能监听到ThirdView的点击事件,写你的更新逻辑 print("ThirdView按钮被点击了,FirstView收到通知") } ) } } } struct SecondView: View { @Binding var bindSecondView: Bool // 接收上层传的回调,再往下传给ThirdView var onThirdViewButtonClick: () -> Void var body: some View { Button { bindSecondView = false } label: { Text("Click here to dismiss sheet") } ThirdView(onButtonClick: onThirdViewButtonClick) } } struct ThirdView: View { // 定义点击回调属性 var onButtonClick: () -> Void var body: some View { Button { // 点击时触发回调 onButtonClick() } label: { Text("By clicking this button in third view, first view should know about this so I can do some updates in first view") } } }
方案2:@Binding 逐层传递状态
如果点击后需要同时修改FirstView的某个状态值,可以直接把状态通过Binding逐层往下传:
struct FirstView: View { @State var openSecondView: Bool = false // 要被ThirdView修改的状态 @State var thirdViewButtonClicked: Bool = false var body: some View { VStack { Text("ThirdView是否点击:\(thirdViewButtonClicked ? "是" : "否")") Button { openSecondView = true } label: { Text("Click here to show second view") } } .sheet(isPresented: $openSecondView) { SecondView( bindSecondView: $openSecondView, thirdViewButtonClicked: $thirdViewButtonClicked ) } } } struct SecondView: View { @Binding var bindSecondView: Bool @Binding var thirdViewButtonClicked: Bool var body: some View { Button { bindSecondView = false } label: { Text("Click here to dismiss sheet") } ThirdView(buttonClicked: $thirdViewButtonClicked) } } struct ThirdView: View { @Binding var buttonClicked: Bool var body: some View { Button { buttonClicked = true } label: { Text("点击通知FirstView") } } }
方案3:@EnvironmentObject 全局环境对象(适合层级深、多组件共享状态的场景)
如果你的视图层级超过3层,或者多个地方都需要监听这个事件,用环境对象避免逐层传递的麻烦:
首先定义ObservableObject类:
class ViewEventModel: ObservableObject { // 发布事件,所有监听的视图都能收到 @Published var thirdViewButtonClicked = false }
视图层实现代码:
struct FirstView: View { @State var openSecondView: Bool = false @StateObject private var eventModel = ViewEventModel() var body: some View { VStack { Text("ThirdView是否点击:\(eventModel.thirdViewButtonClicked ? "是" : "否")") Button { openSecondView = true } label: { Text("Click here to show second view") } } .sheet(isPresented: $openSecondView) { SecondView(bindSecondView: $openSecondView) .environmentObject(eventModel) // 注入环境对象,所有子视图都可以自动继承读取 } // 监听状态变化触发逻辑 .onChange(of: eventModel.thirdViewButtonClicked) { newValue in if newValue { print("收到ThirdView点击事件") // 执行你需要的更新逻辑 } } } } struct SecondView: View { @Binding var bindSecondView: Bool var body: some View { Button { bindSecondView = false } label: { Text("Click here to dismiss sheet") } ThirdView() // 不需要手动传递,环境对象自动继承 } } struct ThirdView: View { // 直接读取环境对象 @EnvironmentObject var eventModel: ViewEventModel var body: some View { Button { eventModel.thirdViewButtonClicked = true } label: { Text("点击通知FirstView") } } }
内容的提问来源于stack exchange,提问作者user4150758
相关产品推荐
相关产品推荐

