从 @Binding var 修改 @State var 不会刷新 SwiftUI 中的视图

Posted

技术标签:

【中文标题】从 @Binding var 修改 @State var 不会刷新 SwiftUI 中的视图【英文标题】:Modifying a @State var from a @Binding var isn't refreshing the view in SwiftUI 【发布时间】:2019-12-06 18:38:01 【问题描述】:

所以我有一个 ParentView,其中包含一个 FilterBar 和一个列表。它看起来像这样:

struct ParentView: View 
    @State var listCellModels: [ListCellModel]

    // Both these vars are passed to the FilterBar and adjusted by the FilterBar
    @State var isEditing: Bool = false
    @State var selectedType: FilterType = .none

    // When selected type is changed, I need to reload the models in the list with the new filter
    private var filteredModels: [ListCellModel] 
        return listCellModels.filter
            (selectedType.rawValue == 0 || $0.approved.rawValue == selectedType.rawValue)
        
    

    var body: some View 
        VStack 
            FilterBar(isEditing: $isEditing, selectedType: $selectedType)

            // All the items in the list are buttons that display a custom view I had
            // this works fine, and when isEditing is changed the view DOES update
            List(filteredModels)  model in
                Button(action: 
                    // Does a thing
                , label: 
                    ListViewCell(model: model, isEditing: self.$isEditing)
                )
            
        
    

我的过滤器栏只是一个简单的 HStack,带有几个修改变量的按钮

struct FilterBar: View 
    @Binding var isEditing: Bool
    @Binding var selectedType: FilterType

    var body: some View 
        HStack(alignment: .center) 
            Button(action: 
                self.selectedType = FilterType.init(rawValue: (self.selectedType.rawValue + 1) % 4)!
            , label: 
                Text("Filter: \(selectedType.name)")
            ).padding(.top).padding(.leading)

            Spacer()

            Button(action: 
                self.isEditing = !self.isEditing
            , label: 
                Text(!isEditing ? "Edit" : "Done")
            ).padding(.top).padding(.trailing)
        
    

当我点击更改 isEditing 的按钮时,列表中的所有单元格都会更新以显示其“正在编辑”状态,但是当我点击按钮更改 selectedType 时,父视图中的变量确实会更新,因为我'在调试器中观察到 - 但是视图不会重新加载。所以看起来旧过滤器仍在应用中。

是否有任何理由更新此 @State 变量不会重新加载视图?

有什么解决办法吗?

【问题讨论】:

这是因为selectedTypebody中的任何地方都没有使用,计算属性filteredModels在这里无关紧要。 @State 只有在这个 View body 中使用才会影响 View,否则它只是属性。 @Asperi 我认为它可能是这样的......它被用于我初始化 FilterBar 的地方 - 但我想这还不够好? @Asperi 是添加一个无意义的解决方案,如果检查 selectedType 并且始终为 true 或其他内容,那么视图会重新加载? 你能提供一个最少可运行代码的git吗? (包括你使用的所有类型) @Asperi 我刚刚再次尝试了你几天前给我的答案,结果证明你是对的 - 它确实有效,我还有其他东西让它看起来好像没有。如果你看到这个,你可以转发它以获得赏金。 【参考方案1】:

嗯,这就像...解决方法...但是为了测试,请尝试

FilterBar(isEditing: $isEditing, selectedType: $selectedType)
if selectedType != .none 
   EmptyView()

一般来说,引入视图模型为ObservableObject 并在其中包含filteredModels@Published 是正确的,因此您的FilterBar 更改了该属性,这将自动刷新ParentView

【讨论】:

以上是关于从 @Binding var 修改 @State var 不会刷新 SwiftUI 中的视图的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI:属性装饰器的理解@State,@Binding,@ObservedObject,@Published,@Environment,@EnvironmentObject

将 @State 属性的 @Binding 值从容器视图传递到其子视图

无法更新/修改 SwiftUI 视图的 @state var

当从 GeometryReader 中进行更改时,SwiftUI 不会反映对 @Binding @State 变量的更改

Swift didSet for var 使用 @Binding 在子级中更改

使用 @Binding var 初始化 SwiftUI 类