swift - 如何在 SwiftUI 中选择性地传入绑定(bind)?

标签 swift swiftui

我有一个内部管理跟踪当前索引的@State 变量的 View 。所以像:

struct ReusableView: View {

    @State var index: Int = 0

    var body: some View {
        Text("The index is \(self.index)"
        // A button that changes the index
    }

}

此 View 将在整个应用程序中重复使用。有时父 View 需要访问索引,所以我将它重构如下:

struct ParentView: View {

    @State var index: Int = 0

    var body: some View {
      ReusableView($index)
    }

}

struct ReusableView: View {

    @Binding var index: Int

    var body: some View {
        Text("The index is \(self.index)"
        // A button that changes the index
    }

}


问题

我不想将父 View 强制为 总是 保持索引的状态。换句话说,我希望有选择地允许父 View 负责状态变量,但默认使用可重用 View 来维护状态,以防父 View 不关心索引。

试图

我尝试以某种方式初始化可重用 View 上的绑定(bind),以防父 View 不提供绑定(bind):

struct ReusableView: View {

    @Binding var index: Int

    init(_ index: Binding<Int>? = nil) {
        if index != nil {
            self._index = index
        } else {
            // TODO: Parent didn't provide a binding, init myself.
            // ?
        }
    }

    var body: some View {
        Text("The index is \(self.index)"
        // A button that changes the index
    }

}

谢谢!

最佳答案

您想要实现的主要问题是,当索引由父级处理时,您的 View 需要对其进行@Binding,但是当它处理索引本身时,它需要@State。有两种可能的解决方案。

如果 View 在没有索引属性时可以忽略它:

struct ReusableView: View {

    @Binding var index: Int?

    init(_ index: Binding<Int?>) {
        self._index = index
    }

    init() {
       self._index = .constant(nil)
    }

    var body: some View {
        VStack {
            index.map { Text("The index is \($0)") }
        }
    }   
}

优点是它非常简单——只有两个初始化器,但是当它由 ResusableView 本身处理时,你不能更改索引的值(它是一个常量)。

如果 View 在没有 index 属性时不能忽略它:
struct ReusableView: View {

    private var content: AnyView

    init(_ index: Binding<Int>? = nil) {
        if let index = index {
            self.content = AnyView(DependentView(index: index))
        } else {
            self.content = AnyView(IndependentView())
        }
    }

    var body: some View {
        content
    }

    private struct DependentView: View {

        @Binding var index: Int

        var body: some View {
            Text("The index is \(index)")
        }
    }

    private struct IndependentView: View {

        @State private var index: Int = 0

        var body: some View {
            Text("The index is \(index)")
        }
    }

}

明显的优势是您有一个可以绑定(bind)到值或将其作为自己的状态管理的 View 。如您所见,ReusableView 只是两个不同 View 的包装器,一个管理自己的@State,一个绑定(bind)到其父 View 的@State。

关于swift - 如何在 SwiftUI 中选择性地传入绑定(bind)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58983538/

相关文章:

Swift:如何访问仅使用一个函数以编程方式创建的多个 UISwitch

swift - 将可选绑定(bind)转换为非可选绑定(bind)

ios - DateFormatter 不返回 "HH:mm:ss"的日期

swift - 为什么我的 Playground 在 NSRange() 上崩溃

json - 纠结于如何使用 api 响应进行调用以从不同的链接检索响应

ios - 如何指定或更改按钮 SwiftUI 的可点击区域

macos - SwiftUI:窗口关闭时运行代码 macOS

swift - 我可以将 Snapchat SDK (SnapKit) 与 SwiftUI 一起使用吗?

ios - 我可以复制一个 .db 文件到我的项目的根目录,然后插入或删除它的数据吗?

swift - MKMapView 不是在 Swift 中缩小 map 时的聚类注释