I want to make a custom DisclosureGroup that has the same functionality as the default DisclosureGroup but allows me to change the color text or even put an image instead of a string.
Because DisclosureGroup does not allow me to remove the blue arrow indicator on the left, and it has limitations.
The default DisclosureGroup right now is:
struct ContentView: View {
@State private var revealDetails = false
var body: some View {
DisclosureGroup("Show Terms", isExpanded: $revealDetails) {
Text("Long terms and conditions here long terms and conditions here long terms and conditions here long terms and conditions here long terms and conditions here long terms and conditions here.")
}
}
}
I want to be able to do something like this:
struct ContentView: View {
@State private var isExpanded = false
var body: some View {
CustomDisclosureGroup(isExpanded: $isExpanded, actionOnClick: {
isExpanded.toggle()
print("do something else")
}, prompt: {
HStack {
Text("this is a custom row")
.foregroundColor(Color.white)
Spacer()
Image("customArrow")
.resizable()
.frame(width: 12, height: 12)
}
.background(Color.blue)
}, expandedView: {
VStack {
Text("this is also a custom view")
Text("another one")
}
.background(Color.red)
})
}
}
CodePudding user response:
After some searching and coding I created this struct that satisfies my needs and acts very similarly to the default DisclosureGroup in SwiftUI.
Here is the usage of it:
struct ContentView: View {
@State private var isExpanded = false
@AppStorage("timesClicked") private var timesClicked = 0
var body: some View {
ScrollView {
CustomDisclosureGroup(animation: .easeInOut(duration: 0.2), isExpanded: $isExpanded) {
isExpanded.toggle()
timesClicked = 1
} prompt: {
HStack(spacing: 0) {
Text("How to open an account in your application?")
Spacer()
Text("?")
.fontWeight(.bold)
.rotationEffect(isExpanded ? Angle(degrees: 180) : .zero)
}
.padding(.horizontal, 20)
} expandedView: {
Text("you can open an account by choosing between gmail or ICloud when opening the application")
.font(.system(size: 16, weight: .semibold, design: .monospaced))
}
}
}
}
you can use it where ever you want by just implementing this struct in your project:
struct CustomDisclosureGroup<Prompt: View, ExpandedView: View>: View {
@Binding var isExpanded: Bool
var actionOnClick: () -> ()
var animation: Animation?
let prompt: Prompt
let expandedView: ExpandedView
init(animation: Animation?, isExpanded: Binding<Bool>, actionOnClick: @escaping () -> (), prompt: () -> Prompt, expandedView: () -> ExpandedView) {
self.actionOnClick = actionOnClick
self._isExpanded = isExpanded
self.animation = animation
self.prompt = prompt()
self.expandedView = expandedView()
}
var body: some View {
VStack(spacing: 0) {
prompt
if isExpanded{
expandedView
}
}
.clipped()
.contentShape(Rectangle())
.onTapGesture {
withAnimation(animation) {
actionOnClick()
}
}
}
}
CodePudding user response:
While DisclosureGroup doesn't give you the full flexibility to customize it, there are still a few things you can do:
If all you need is red arrow instead of blue, you can simply set
.tint(.red)for it.If you need information other than text in the label, you can actually init them with:
For more sophisticated customizations, if you are running on iOS 16 or later, consider adopting DisclosureGroupStyle.
- Example:
struct CustomDisclosureGroupStyle<Label: View>: DisclosureGroupStyle { let button: Label func makeBody(configuration: Configuration) -> some View { HStack { configuration.label Spacer() button .rotationEffect(.degrees(configuration.isExpanded ? 90 : 0)) } .contentShape(Rectangle()) .onTapGesture { withAnimation { configuration.isExpanded.toggle() } } if configuration.isExpanded { configuration.content .padding(.leading, 30) .disclosureGroupStyle(self) } } } struct ContentView: View { var body: some View { DisclosureGroup { //... } .disclosureGroupStyle(CustomDisclosureGroupStyle(button: Text("ok"))) } }

