如何使@Binding变量刷新视图

时间:2020-11-05 17:46:07

标签: swiftui

据我了解,如果需要从视图内部更新视图模型,则需要使其成为绑定变量。

模型。

enum Options: Int, Identifiable, Equatable, CaseIterable {
    case option1 = 1
    case option2 = 2
    case option3 = 3
    case option4 = 4
    
    var id: String { "\(self.rawValue)" }
}

class TestViewModel:  ObservableObject {
    var selectedOption = Options.option1
    ...
}

视图。


struct TestView: View {
    @Binding var viewModel: TestViewModel
    @State var selectedOption = Options.option1

    var body: some View {
        
        Picker("Option 1", selection: $viewModel.selectedOption) {
            ForEach(Options.allCases, id: \.id) { value in
                Text(value.id)
                    .tag(value)
            }
        }
        Text("Selected Option: \(viewModel.selectedOption.rawValue)")
        
        Picker("Option 2", selection: $selectedOption) {
            ForEach(Options.allCases, id: \.id) { value in
                Text(value.id)
                    .tag(value)
            }
        }
        Text("Selected Option: \(selectedOption.rawValue)")
    }
        
}

  • 在第一个纠察栏中选择一个值,视图不会刷新。
  • 在第二个选择器中选择一个值,视图将刷新(按预期)

如何使用@Binding更新视图以更新视图?

我想出了可行的解决方案,但对我来说并不好。

...
 let b = Binding<Options>(
            get: {
                viewModel.selectedOption
            },
            set: {
                viewModel.selectedOption = $0
                selectedOption = $0 // << this forces the view to refresh
            }
        )

 Picker("Speed 1", selection: b) {
            ForEach(Options.allCases, id: \.id) { value in
                Text(value.id)
                    .tag(value)
            }
        }
...

2 个答案:

答案 0 :(得分:2)

ObservableObjectObservedObject包装器配对使用。在这种情况下,视图模型成为视图真相的来源。所以...

  1. 发布财产
class TestViewModel:  ObservableObject {
    @Published var selectedOption = Options.option1     // << here !!
    ...
}
  1. 制作由ObservedObject包装的视图模型
struct TestView: View {
    @ObservedObject var viewModel: TestViewModel
  1. 直接绑定选择器以查看模型
 Picker("Speed 1", selection: $viewModel.selectedOption) {
            ForEach(Options.allCases, id: \.id) { value in
                Text(value.id)
                    .tag(value)
            }
        }

答案 1 :(得分:0)

我不确定您是否有合理的理由在此处使用ObservableObject,但是可以通过使用structState变量轻松达到相同的结果:

struct TestViewModel {

    var selectedOption = Options.option1
}

struct TestView: View {

    @State var viewModel: TestViewModel

    var body: some View {
        Picker("Option 1", selection: $viewModel.selectedOption) {
            ForEach(Options.allCases, id: \.id) { value in
                Text(value.id)
                    .tag(value)
            }
        }
    }
}