I need to have a custom DisclosureGroup. I have a version of it working like this:
public struct CustomDisclosureGroup<LabelContent: View, Content: View>: View {
var label: LabelContent
var content: Content
@Binding var isExpanded: Bool
public init(isExpanded: Binding<Bool>, @ViewBuilder label: () -> LabelContent, @ViewBuilder content: () -> Content) {
self.label = label()
self.content = content()
self._isExpanded = isExpanded
}
public init(labelString: String, isExpanded: Binding<Bool>, @ViewBuilder content: () -> Content) {
self.init(isExpanded: isExpanded, label: { Text(labelString) as! LabelContent }, content: content)
}
public var body: some View {
DisclosureGroup(isExpanded: $isExpanded) {
content
} label: {
label
}
}
}
@main
struct TestDisclosureApp: App {
@StateObject var topModel = TopModel()
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
@EnvironmentObject var topModel: TopModel
@State var isExpanded1 = false
@State var isExpanded2 = false
var body: some View {
CustomDisclosureGroup(isExpanded: $isExpanded1, label: { Text("Label") }) {
HStack {
Text("Content1")
}
}
.padding()
// CustomDisclosureGroup<Text, View>(labelString: "Label", isExpanded: $isExpanded2) {
// HStack {
// Text("Content2")
// }
// }
// .padding()
}
}
I have two initializers. The first woks fine but the second one is giving me problems. Xcode somewhat forced me to add the type cast "as! LabelContent" which doesn't look nice. But, more importantly, I can't get it to work. Uncomment the second example to see the error message.
How can I declare an init to just take String instead of a LabelContent (i.e.: Label)?
If you use where
to restrict the types you can define the type in the init
public struct CustomDisclosureGroup<LabelContent, Content>: View where LabelContent : View, Content : View{
Then in the init
you can say that where LabelContent == Text
public init(isExpanded: Binding<Bool>, @ViewBuilder label: () -> LabelContent, @ViewBuilder content: () -> Content) {
self.label = label()
self.content = content()
self._isExpanded = isExpanded
}
public init(labelString: String, isExpanded: Binding<Bool>, @ViewBuilder content: () -> Content) where LabelContent == Text {
self.init(isExpanded: isExpanded, label: { Text(labelString)
}, content: content)
}
Full code below
public struct CustomDisclosureGroup<LabelContent, Content>: View where LabelContent : View, Content : View{
var label: LabelContent
var content: Content
@Binding var isExpanded: Bool
public init(isExpanded: Binding<Bool>, @ViewBuilder label: () -> LabelContent, @ViewBuilder content: () -> Content) {
self.label = label()
self.content = content()
self._isExpanded = isExpanded
}
public init(labelString: String, isExpanded: Binding<Bool>, @ViewBuilder content: () -> Content) where LabelContent == Text {
self.init(isExpanded: isExpanded, label: { Text(labelString)
}, content: content)
}
public var body: some View {
DisclosureGroup(isExpanded: $isExpanded) {
content
} label: {
label
}
}
}
Your second usage would look like this, there is no need to add types.
CustomDisclosureGroup(labelString: "Label", isExpanded: $isExpanded2) {
HStack {
Text("Content2")
}
}
.padding()