I'm trying to build a new SwiftUI View that encapsulates a Toggle.
The Toggle accesses a collection so that it can show up in a mixed state.
I'm having difficulties constructing the proper KeyPath.
I've build the view as follows:
struct CornersView<C>: View where C: RandomAccessCollection {
@Binding var sources: C
let keyPath: KeyPath<C.Element, Binding<ApertureCorners>>
var body: some View {
Toggle(sources: sources, isOn: keyPath.appending(path: \.upperLeftActive), label: {})
}
}
#Preview {
@State var sources = [ApertureCornerTreatment(radius: 1, corners: [], chamfered: false)]
return CornersView(sources: $sources, keyPath: \.corners)
}
This gives me the following error on the last line in the preview:
Key path value type 'ApertureCorners' cannot be converted to contextual type 'Binding<ApertureCorners>'
Oddly enough, if I would want a Toggle on chamfered in the preview I would write:
Toggle(sources: $sources, isOn: \.chamfered, label: {}), which looks very similar to the current preview.
What did I do wrong?
In the future, please post a complete example. I've stubbed in some code to be able to reproduce your error, but you should have included all this in your post:
With those definitions, I can reproduce your error:
The location of the error isn't really where you have a problem, though.
The main problem is in your call to
Toggle(line-wrapped for readability):You're passing
sources, not$sources. So you're passing a plain array (type[ApertureCornerTreatment]) toToggle. TheisOnargument therefore needs to be aKeyPath<ApertureCornerTreatment, Binding<Bool>>.There are no
Bindings inApertureCornerTreatmentorApertureCorners, nor is there any obvious way to create one, so you're not going to be able to create a key path with that type.The trick, which is not explained in
Toggles documentation, is this: whatever you pass as thesourcesargument toToggleneeds to be not just aRandomAccessCollection, but also something that can createBindings.The only type I'm aware of that conforms to
RandomAccessCollectionand can createBindings is…Bindingitself, when itsValuetype is itself aRandomAccessCollection.So, let's change the code to pass
$sourcestoToggle, and get two new errors:We fix these errors by adding a requirement that
Cconform toMutableCollection, and by changing the type of thekeyPathproperty:With those changes, Swift accepts the
#Preview.