I need to pass a default value for a container view in SwiftUI but it seems to be impossible. I tried some solutions with no luck.
This is my code so far
struct BabbuzziView<LabelContent: View, Content: View, DividerContent: View>: View, AutoClosingGroup {
@ObservedObject var state: DisclosingGroupState
var index: Int
var buttonIconOpen: String = Asset.Images.ProductDetail.minusIcon.name
var buttonIconClosed: String = Asset.Images.ProductDetail.plusIcon.name
var buttonColor: Color = Color(Asset.Colors.GeneralComponents.ProducAdditionalInfoView.iconColor.color)
var imageSize: CGFloat = 24
var label: LabelContent
var divider: DividerContent
var content: Content
init(
state: DisclosingGroupState,
index: Int,
@ViewBuilder label: () -> LabelContent,
@ViewBuilder content: () -> Content,
@ViewBuilder divider: () -> DividerContent) {
self.state = state
self.index = index
self.label = label()
self.content = content()
self.divider = divider()
}
private func with(_ mutate: (inout Self) -> ()) -> Self {
var copy = self
mutate(©)
return copy
}
func buttonIconOpen(_ iconOpenName: String) -> Self {
return self.with { $0.buttonIconOpen = iconOpenName }
}
func buttonIconClosed(_ iconClosedName: String) -> Self {
return self.with { $0.buttonIconClosed = iconClosedName }
}
func buttonColor(_ buttonColor: Color) -> Self {
return self.with { $0.buttonColor = buttonColor }
}
func imageSize(_ size: CGFloat) -> Self {
return self.with { $0.imageSize = size }
}
func divider<Divider: View>(@ViewBuilder _ divider: () -> Divider) -> BabbuzziView<LabelContent, Content, Divider> {
return .init(state: state, index: index, label: { label }, content: { content }, divider: divider)
}
var body: some View {
VStack(alignment: .leading, spacing: 0){
VStack(alignment: .leading, spacing: 0){
HStack() {
label
Spacer()
Button(action: {
withAnimation {
state.toggleView(at: index)
}
}) {
Image(closed ? buttonIconClosed : buttonIconOpen)
.resizable()
.frame(width: imageSize, height: imageSize)
.aspectRatio(contentMode: .fit)
.foregroundColor(buttonColor)
}
}
.padding(.horizontal, 16)
if !closed {
content
.padding(.horizontal, 16)
}
Spacer()
.frame(height: 21)
divider
}
}
}
}
extension BabbuzziView where DividerContent == EmptyView {
init(state: DisclosingGroupState,
index: Int,
@ViewBuilder label: () -> LabelContent,
@ViewBuilder content: () -> Content) {
self.state = state
self.index = index
self.label = label()
self.content = content()
self.divider = { EmptyView() }()
}
}
The view should mimic a DisclosureGroup but with more control on it (button glyph, divider and some other tweaks in the future)
and should be used as
BabbuzziView(state: state,
index: 0,
label: {
Text("test title.uppercased())
},
content: {
Text("THIS IS THE CONTENT)
})
But XCode complains with
No exact matches in reference to static method ‘buildExpression’
I put here also code of AutoClosingGroup
stuff for completion but I think it is not related to the error
class DisclosingGroupState: ObservableObject {
@Published var selectedIndex: Int?
func toggleView(at index: Int) {
if selectedIndex == index {
selectedIndex = nil
} else {
selectedIndex = index
}
}
}
protocol AutoClosingGroup {
var state: DisclosingGroupState { get set }
var index: Int { get }
var closed: Bool { get }
}
extension AutoClosingGroup {
var closed: Bool {
state.selectedIndex != index
}
}
I wrote that code based on this reply by Rob Mayoff but I cannot understand what I’m doing wrong.