如何在视图中使用Swift参数包

vaj7vani  于 2023-10-15  发布在  Swift
关注(0)|答案(1)|浏览(141)

我想轻松地为SwiftUI预览提供可变绑定到我的视图(这样预览是交互式的,不像传递.constant(...)绑定)。我遵循了BindingProvider方法,它允许一次一个值,如下所示:

#Preview {
    BindingProvider(true) { binding in
        SomeToggleView(toggleBinding: binding)
    }
}

最好传入多个要绑定的值,如下所示

#Preview {
    BindingProvider(true, "text") { toggleBinding, textFieldBinding in
        SomeToggleAndTextFieldView(toggleBinding: toggleBinding, textFieldBinding: textFieldBinding)
    }
}

到目前为止,我已经得到了这段代码,但它没有编译,只是说“Command SwiftCompile failed with a non-zero exit code

struct BindingProvider<each T, Content: View>: View {
    
    @State private var state: (repeat State<each T>)
    
    private var content: ((repeat Binding<each T>)) -> Content
    
    init(_ initialState: repeat each T, 
         @ViewBuilder content: @escaping ((repeat Binding< each T>)) -> Content)
    {
        self.content = content
        self._state = State(initialValue: (repeat State(initialValue: each initialState)))
    }
    
    var body: Content {
        content((repeat (each state).projectedValue))
    }
}

也许我做错了什么,或者这只是一个编译器的问题?任何帮助将不胜感激!

e3bfsja2

e3bfsja21#

编译器似乎还不能管理some Protocol结构和参数包。具体的视图类型有帮助,所以只需替换

var body: some View {

var body: Content {

没有类型擦除的解决方案不能提供平滑的绑定展开.如果不枚举tuple的元素,你就不能打开它。我认为这将是不可能的,直到@ dynamicsoftware将学习如何处理参数包。

struct BindingProvider<each T, Content: View>: View {
    
    @State private var state: (repeat each T)
    private var content: (_ binding: Binding<(repeat each T)>) -> Content
    
    init(_ initialState: repeat each T, @ViewBuilder content: @escaping (Binding<(repeat each T)>) -> Content) {
        self.content = content
        self._state = State(initialValue: (repeat each initialState))
    }
    
    var body: Content {
        self.content($state)
    }
}

#Preview {
    BindingProvider(0, true) { bind in
        let (count, isOn) = (bind.0, bind.1)
        Stepper("", value: count)
        Toggle("", isOn: isOn)
    }
}

下面是类型擦除和枚举元组值的解决方案:

struct BindingProvider<each T, Content: View>: View {
    
    @State private var states: [Any]
    private var content: ((repeat Binding<each T>)) -> Content
    
    init(_ initialState: repeat each T, @ViewBuilder content: @escaping (repeat Binding<each T>) -> Content) {
        self.content = { (args: (repeat Binding<each T>)) in
            content(repeat each args)
        }
        
        // convert arguments to an array
        var states = [Any]()
        repeat states.append(each initialState as Any)
        _states = State(initialValue: states)
    }
    
    // Specify body type as Content. Compile time error otherwise
    var body: Content {
        content((repeat each makeBindings()))
    }
    
    private func makeBindings() -> (repeat Binding<each T>) {
        var index = 0
        func makeBinding<Result>(_ index: inout Int) -> Binding<Result> {
            let currentIndex = index
            index += 1
            return Binding<Result> {
                states[currentIndex] as! Result
            } set: { newValue in
                states[currentIndex] = newValue
            }
        }
        
        return (repeat makeBinding(&index) as Binding<each T>)
    }
}

#Preview {
    BindingProvider(18, "Hello") { $temperature, $greeting in
        VStack(alignment: .leading) {
            Text("\(greeting), the temperature is \(temperature)º")
            TextField("Greeting", text: $greeting)
            Stepper("\(temperature)", value: $temperature)
        }
        .padding()
    }
}

解决方案是强类型的,即使类型擦除发生在幕后。索引也是安全的,因为它被限制在任何示例的生命周期中相同的“A“的数量(重复每个A)。

相关问题