I try to create something similar to TabView
. I want to have the possibility to pass a selection as a @Binding
, so that you can control the selection like this:
@State var selection = 0
...
var body: some View {
CustomTabView(selection: $selection) { .... }
}
But I also would like to leave it without a binding:
var body: some View {
CustomTabView { ... }
I saw, that SwiftUI itself solves it with different initializers:
public init<C>(selection: Binding<SelectionValue>, @TabContentBuilder<SelectionValue> content: () -> C) where Content == TabContentBuilder<SelectionValue>.Content<C>, C : TabContent
....
public init<C>(@TabContentBuilder<Never> content: () -> C) where SelectionValue == Never, Content == TabContentBuilder<Never>.Content<C>, C : TabContent
I would like to do the same. But how can I control the selection?
struct CustomTabView: View {
init(@CustomTabBuilder tabs: () -> [CustomTab]) {
self._selectedTab = // ??????
self.tabs = tabs()
}
init(selection: Binding<Int>, @CustomTabBuilder tabs: () -> [CustomTab]) {
self._selectedTab = selection
self.tabs = tabs()
}
Just make the Binding
optional.
struct CustomSelectableView: View {
let items: [String]
private let _selection: Binding<String>?
init(items: [String], selection: Binding<String>? = nil) {
self.items = items
self._selection = selection
}
...
}
Check for nil in body
:
var body: some View {
if let _selection {
BindingSelection(items: items, selection: _selection)
} else {
StateSelection(items: items)
}
}
BindingSelection
is where you put the actual body of your view, and StateSelection
will reuse BindingSelection
and pass its own @State
to it.
private struct BindingSelection: View {
let items: [String]
@Binding var selection: String
var body: some View {
// Write your view here...
/* as a macOS example:
List(items, id: \.self, selection: $selection) {
Text($0)
}
*/
}
}
private struct StateSelection: View {
let items: [String]
@State private var selection: String = ""
var body: some View {
// reuse BindingSelection here, so we avoid code duplication
BindingSelection(items: items, selection: $selection)
}
}