SwiftUI首次弹出带@Binding变量的sheet时绑定失效问题
问题原因
这是SwiftUI的sheet(isPresented:content:)接口的已知渲染特性,不属于你的代码逻辑错误:
- SwiftUI的状态更新机制只会在状态变量被视图body的渲染内容依赖时,才触发整个body的重绘。你原始代码的body里没有任何视图用到
showIndex变量,所以点击按钮修改showIndex的值时,ContentView的body不会触发重绘。 sheet(isPresented:content:)的content闭包会在父视图首次渲染时提前捕获变量值,只要父视图body没有重绘,闭包里捕获的showIndex就一直是初始值0,所以首次点击second按钮时,弹出的sheet绑定的是数组第0位的first。- 当你先点击first(和初始index一致无感知)、third按钮弹出sheet后,或者取消Text的注释(
showIndex被视图依赖,修改后触发body重绘),sheet的content闭包会被重新生成,捕获最新的showIndex值,后续表现就恢复正常。
最优解决方案
推荐使用SwiftUI提供的sheet(item:content:)接口实现带动态参数的sheet弹出,这个接口会自动监听item的变化,每次弹出都用最新的参数生成sheet,不会出现值捕获延迟的问题,修改后的代码如下:
struct ContentView: View { @State var array = ["first", "second", "third"] // 把展示索引改为可选类型,作为sheet的触发item @State var selectedIndex: Int? var body: some View { VStack { ForEach (0 ..< array.count, id:\.self) { i in Button("\(array[i])") { // 直接给selectedIndex赋值即可自动弹出sheet selectedIndex = i } } } // 使用item版本的sheet接口 .sheet(item: $selectedIndex, content: { index in SheetView(text: $array[index]) }) .padding() } }
如果要保留原有的isPresented实现,也可以保持你注释的Text代码,哪怕设置Text("\(showIndex)").opacity(0)隐藏视图也能解决问题,但属于取巧方案,不推荐长期使用。
内容的提问来源于stack exchange,提问作者reed-coder
相关产品推荐
相关产品推荐

