Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hide SwiftUI DisclosureGroup Arrow and Remove Default Padding

Tags:

swiftui

I'm trying to make a fully custom list of expandable sections that have projects inside them in SwiftUI. This is how I want it to look in the end:

enter image description here

I think I have the SwiftUI code set up right, but I'm having trouble finding view modifiers to accomplish what I want.

Here is my code with most style modifiers removed for brevity:

List {
  ForEach(sections, id: \.self) { section in
  
    DisclosureGroup(isExpanded: $expand) {
      ForEach(section.projectArray, id: \.self) { project in
        //--- Projects ---
        HStack{
          Image("project")
          Text(project.wrappedName)
          Spacer()
        }
        .padding(EdgeInsets(top: 0, leading: 0, bottom:0, trailing: 0))
      } 
    } label: {
      //--- Sections ---
      HStack{
        Text(section.wrappedName)
        Spacer()
        //Custom Toggle Arrow
        Button(action: {
          //Toggle logic
        }){
          if expand{
            Image("section-open")
          }else{
            Image("section-closed")
          }
        }
      }
      .padding(0)
    }
  } 
}.listStyle(PlainListStyle())

I can't find anything to change DisclosureGroup that adds a few default styles I don't want:

A - A default expand/collapse arrow

B - When expanded, the DisclosureGroup's label grows horizontally

C - Default padding on the child elements

enter image description here

I checked the docs and don't see a way to remove these default styles. Any ideas how I can pull off this design?

like image 285
Clifton Labrum Avatar asked Nov 15 '22 00:11

Clifton Labrum


1 Answers

This is a hacky way which won't work inside List but it will work inside LazyVStack and other stacks.

import SwiftUI

struct ContentView: View {
    @State var isExpanded: Bool = false
    var body: some View {
        ScrollView {
            LazyVStack {
                DisclosureGroup("Disclosure", isExpanded: $isExpanded) {
                    Text("Hello, world!")
                        .padding()
                }
                .buttonStyle(DisclosureStyle(isExpanded: $isExpanded))

            }
            .padding(.horizontal)
        }
    }
}

struct DisclosureStyle: ButtonStyle {
    @Binding var isExpanded: Bool
    func makeBody(configuration: Configuration) -> some View {
        HStack {
            Image(systemName: isExpanded ? "chevron.down.circle" : "chevron.right.circle")
                .if(configuration.isPressed) { image in
                    image.symbolVariant(.fill)
                }
                .foregroundStyle(isExpanded ? .green : .accentColor)
            Spacer()
            let font = isExpanded ? Font.headline.monospaced() : .headline
            configuration.label
                .font(font).id(font)
                .overlay(alignment: .topTrailing) {
                    Rectangle().fill(.bar).frame(maxWidth: 30)
            }
            .foregroundStyle(isExpanded ? .green : .accentColor)
        }
        .background(.bar)
    }
}

extension View {
    @ViewBuilder func `if`<Content: View>(_ condition: Bool, transform: (Self) -> Content) -> some View {
        if condition {
            transform(self)
        } else {
            self
        }
    }
}

The result looks like this: Custom DisclosureGroup

like image 109
Paul B Avatar answered Dec 09 '22 20:12

Paul B