【问题标题】:Passing a BindableObject to the views将 BindableObject 传递给视图
【发布时间】:2019-10-24 04:20:36
【问题描述】:

从 Apple 的会话和教程中,我们有两个选项可以将 BindableObject 传递给视图。

  1. 使用声明 BindableObject 作为具有 @ObjectBinding 包装器的层次结构顶部视图中的事实来源,并将其传递给声明 @Binding 的其他视图。
  2. 使用声明BindableObject 作为层次结构顶部视图中的事实来源,使用@EnviromentObject 包装器,使用.enviroment(BindableObject) 修饰符初始化顶部视图并将其传递给其他视图或声明@Binding,或使用@ 987654329@(在这种情况下,BindableObject 将由 SwiftUI 自动分配,我们不需要在 init 时传递它)。

来自Handling User Input tutorial,如果我们有带有项目列表的BindableObject,并且我们想要更改其他视图(或RowView甚至单独屏幕)上的项目之一,我们需要:

  1. 使用上述任何一种方式将BindableObject 传递到更深层的视图。
    1. 将所选项目传递到此视图。
    2. 通过在BindableObject 列表中查找项目,将项目的属性与BindingView 绑定。

一些代码让问题更清楚:

消息模型和BindableObject

struct Message: Identifiable {
    var id: String
    var toggle: Bool = true
}

class MessageStore: BindableObject {

  let didChange = PassthroughSubject<MessageStore, Never>()

  var messagesList: [Message] = testData {
    didSet {
      didChange.send(self)
    }
  }
}

表示项目列表的MessageView 结构消息视图

 : View {

    @EnvironmentObject var messageStore: MessageStore

    var body: some View {
        NavigationView {
            List(messageStore.messagesList) { message in
                NavigationButton(destination: Text(message.id)) {
                    MessageRow(message: message)
                }
            }
            .navigationBarTitle(Text("Messages"))
        }
    }
}

MessageRow 有一个 Toggle 来更新特定项目的状态 in out BindableObject

struct MessageRow: View {

    @EnvironmentObject var tags: MessageStore
    var message: Message

    var messageIndex: Int {
        tags.messagesList.firstIndex { $0.id == message.id }!
    }


    var body: some View {
       Toggle(isOn: self.$tags.messagesList[self.messageIndex].toggle) {
           Text("Test toogle")
       }
    }

}

我上面提到的教程中显示了这种方法。

问题: 我想将 Message 作为@Binding 单独传递以直接在子视图中使用它,但我无法实现这一点。 我变得有些困惑。将BindableObject 和选定项目传递给任何视图(应该处理绑定)以稍后使用索引从BindableObject 绑定项目是否是正确的方法?有没有其他方法可以不传递完整的BindableObject,而是传递其中的一部分并绑定这部分(它应该是事实的来源),在我们的例子中,这部分是Message

【问题讨论】:

  • 感谢您发布此信息。我刚刚遇到了同样的问题,并且遇到了完全相同的令人困惑的问题。 Apple 自己的教程似乎支持了一种做法,坦率地说,我认为他们应该为此感到尴尬。他们新的旗舰 UI 系统似乎只适合简单的 UI;无法直接传递绑定的子对象是一个有趣的限制,因此强制对其进行详尽的搜索或将索引传递给它。史蒂夫乔布斯在他的坟墓里旋转。

标签: ios swiftui swift5.1


【解决方案1】:

我认为你过于复杂了。您似乎只需要消息中的切换值。试试这个:

var body: some View {
    NavigationView {
        List(messageStore.messagesList) { message in
            NavigationButton(destination: Text(message.id)) {
                MessageRow(isTogged: $message.toggle)
            }
        }
        .navigationBarTitle(Text("Messages"))
    }
}

struct MessageRow: View {

    @Binding var isToggled: Bool

    var body: some View {
        Toggle(isOn: self.isToggled) {
            Text("Test toogle")
        }
    }
}

【讨论】:

  • 你不能这样做。 MessageRow(isTogged: $message.toggle) 会建议你删除 $,因为本地消息不是可绑定的
  • 另外想象更真实的Message的情况包含一些String字段和toggle,它们都可以在子视图中编辑。我认为在这种情况下我们不能为每个人创建@Binding,但我们也不能使用@Binding var message: Message
  • 嗯,我看过你提到的教程。他们制作了 BindableObject 类来监控模型的变化。如果您添加该功能并省略 $ 符号,您在子视图中所做的更改将自动添加并与您的模型同步。
  • 看起来你误解了我在他们的教程中的问题有一个完整的 BindableObject 和包含在 BindableObject 数组中的子对象。为了使其与子视图一起工作,他们将子对象传递给子视图并使用它在 BindableObject 中查找此子对象的索引。它看起来很奇怪,所以我在问另一种方法来实现这种复杂的数据模型结构。我们的想法是找到好的架构方式,而不仅仅是他们示例中的解决方法
猜你喜欢
  • 2012-06-11
  • 2011-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-01
  • 2011-09-05
  • 2018-01-08
相关资源
最近更新 更多