I am trying to create a custom Picker using a similar approach that Apple is taking. To put in simple terms I am trying to make the Text that is selected Blue and the Text that isn't selected Black.
So I got this far (see code below).
I have the feeling that I am close, but I am missing the last puzzle piece.
struct ContentView: View {
@State private var selectionIndex: Int = 2
var body: some View {
CustomPicker(selection: $selectionIndex) {
Text("1").tag(1)
Text("2").tag(2)
}
}
}
struct CustomPicker<T: Hashable>: View {
@Binding var selection: T
init<Content: View>(selection: Binding<T>, @ViewBuilder content: () -> TupleView<(Content)>) {
self._selection = selection
let content = content() //<-- How to store content to be used in body?
}
init<each Content: View>(selection: Binding<T>, @ViewBuilder content: () -> TupleView<(repeat each Content)>) {
self._selection = selection
let content = content() //<-- How to store content to be used in body?
repeat print(newView(each content.value)) //<-- How to create a new (altered) TupleView?
}
var body: some View {
return Text("Done") //<-- Should return the altered content
}
func newView(_ view: some View) -> some View {
if let tag = tag(view), tag == self.selection {
return view.foregroundColor(.blue)
} else {
return view.foregroundColor(.black)
}
}
func tag(_ view: some View) -> T? {
Mirror(reflecting: view).descendant("modifier", "value", "tagged") as? T
}
}
#Preview {
ContentView()
}
You can use View Extractor to get views out of a
ViewBuilder. Do note that this uses unstable APIs.Here is an example:
Note that here I used
idinstead oftagto identify the view, because it is more convenient this way. The view trait key fortagis an internal type, so it is very difficult to access it. You can try and find a mirror path, but it might be easier to just write your own view trait key:Then you can get the tag this way: