当 @State var 基于 Picker 选择发生变化时,一个视图不会重新呈现

Posted

技术标签:

【中文标题】当 @State var 基于 Picker 选择发生变化时,一个视图不会重新呈现【英文标题】:One view does not rerender when @State var changes based on Picker selection 【发布时间】:2020-01-31 16:48:54 【问题描述】:

尝试使用 SwiftUI 构建一个简单的 MacOS 应用。我有一个包含绑定到 State var 的 Picker 的视图。作为健全性检查,我添加了一个文本视图(矮人一号和卷...itemName),它也应该随着选取器的变化而变化。他们会这样做,但我要重新渲染的视图(FileList)没有。

我怀疑这与我尝试将新的 FileSystemItem(内部类)传递给 FileList 的方式有关。就像 FilePanel 重新渲染时一样,volumeSelection 回到 0,然后应用状态。所以我的问题是我似乎缺少关于这些数据应该如何流动的基本概念。我再次浏览了 WWDC 信息并阅读了其他文章,但我没有看到答案。

所需的行为是更改选择器上的选择应该导致新的 FileSystemItem 显示在 FileList 视图中。什么是让这种情况发生的正确方法?更笼统地说,当 Picker 选择发生变化时,如何让子视图显示新数据?

struct FilePanel: View 

    @State var volumeSelection = 0
    @State var pathSelection = 0

    var volumes = VolumesModel() //should be passed in?
    var dwarves = ["Schlumpy","Wheezy","Poxxy","Slimy","Pervy","Drooly"]

    var body: some View 
        VStack 
            Picker(selection: $volumeSelection, label:
                Text("Volume")
                , content: 
                    ForEach (0 ..< volumes.count()) 
                        Text(self.volumes.volumeAtIndex(index: $0).itemName).tag($0)
                    
            )

            FileList(item:volumes.volumeAtIndex(index: volumeSelection)).frame(minWidth: CGFloat(100.0), maxHeight: .infinity)
            Text(dwarves[volumeSelection])
            Text(volumes.volumeAtIndex(index: volumeSelection).itemName)

        
    
 

struct FileList: View 
    @State var item : FileSystemItem

    var body: some View 
        VStack 
        List(item.childItems)fsi in
            FileCell(expanded:false, item: fsi)
        
        Text(item.itemName)
        
    

【问题讨论】:

我想帮忙,但我不能“只是复制”你的代码并运行它,这并不好玩...... :( 这不是代码运行时发生的问题。问题中描述了该行为。问题在于 SwiftUI 中完成将新值推送(或使其可用)到子视图的正确方法是什么。 【参考方案1】:

@State 是拥有视图的私有状态,FileList 永远不会看到任何变化。

如果VolumesModel 是将FileList.item 转换为绑定(in-out-state)的简单结构可能已经工作(调用者在将@State 传递给依赖项时仍需要将其转换为绑定,使用$):

struct FileList: View 
  @Binding var item : FileSystemItem
  ...

但是,感觉就像VolumesModel 是一个具有一组成员的更复杂的对象。

如果是这样的话,上面的就不够了:

VolumesModel 需要是采用ObservableObject 的类 VolumesModel 的重要成员需要一个可绑定的包装器 (@Published) FileList.item 应该变成@ObservedObject(而不是@State 或@Binding) FilePanel.volumes 也被@ObservedObject 包裹

希望能帮助或至少为您指明正确的方向。

【讨论】:

我认为@State 正在发生类似的事情,因此感谢您的确认。我一直在研究 ObservableObject,但对于我想要完成的(看似)简单的事情来说,这似乎有点矫枉过正。但我想这是我应该追求的。感谢您的建议,我很感激! 您是正确的,FileList 中的 @State 是错误的。您还让我查看了 ObservableObject,我认为从长远来看这是我需要的。谢谢!

以上是关于当 @State var 基于 Picker 选择发生变化时,一个视图不会重新呈现的主要内容,如果未能解决你的问题,请参考以下文章

iOS 15 SwiftUI 3 Picker 绑定在更改@State 值后不起作用

创建一个@State var 区域,即基于两个@State var 宽度,一个@State var 高度

如何让 Picker 使用 ForEach 循环返回 VideoFormat var?

基于vue的颜色选择器vue-color-picker

React Native Picker 不更新状态

为啥我的 SwiftUI 视图不会在更新 @State var 时更新?