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"))) } }