How to fix DisclosureGroup chevron arrow opacity?

136 views Asked by At

I'm currently working on creating an accordion view in SwiftUI, but I've encountered a problem: the default chevron that accompanies the DisclosureGroup appears translucent. I attempted to integrate it into a List, but this approach disrupts my design. Additionally, I tried setting the accent to clear and adding a custom image, but this resulted in misaligned chevron placement — it shifts to the left instead of remaining on the right. Has anyone else experienced this issue and found a solution or workaround? Also, I should mention that my minimum deployment target is iOS 15.

import SwiftUI

struct ContentView: View {
    @State private var isExpanded1 = false
    @State private var isExpanded2 = false
    @State private var isExpanded3 = false
    @State private var isExpanded4 = false

    var body: some View {
        VStack(alignment: .trailing, spacing: 0) {
            // Accordion Section 1
            DisclosureGroup(
                isExpanded: $isExpanded1,
                content: {
                    Text("Details for Services") // Test content for section 1
                },
                label: {
                    accordionLabel(number: "1", title: "Services", isExpanded: isExpanded1)
                }
            )
            
            .padding(16)
            .frame(width: 360, alignment: .top)
            .background(Color.white)

            // Accordion Section 2
            DisclosureGroup(
                isExpanded: $isExpanded2,
                content: {
                    Text("Information on Terms") // Test content for section 2
                },
                label: {
                    accordionLabel(number: "2", title: "Terms", isExpanded: isExpanded2)
                }
            )
            .padding(16)
            .frame(width: 360, alignment: .top)
            .background(Color.white)

            // Accordion Section 3
            DisclosureGroup(
                isExpanded: $isExpanded3,
                content: {
                    Text("Payment Options and Details") // Test content for section 3
                },
                label: {
                    accordionLabel(number: "3", title: "Payment", isExpanded: isExpanded3)
                }
            )
            .padding(16)
            .frame(width: 360, alignment: .top)
            .background(Color.white)

            // Accordion Section 4
            DisclosureGroup(
                isExpanded: $isExpanded4,
                content: {
                    Text("Signature Procedures and Guidelines") // Test content for section 4
                },
                label: {
                    accordionLabel(number: "4", title: "Signatures", isExpanded: isExpanded4)
                }
            )
            .padding(16)
            .frame(width: 360, alignment: .top)
            .background(Color.white)
        }
    }

    @ViewBuilder
    private func accordionLabel(number: String, title: String, isExpanded: Bool) -> some View {
        HStack {
            HStack(spacing: 8) {
                VStack {
                    Text(number)
                        .font(Font.custom("Inter", size: 16).weight(.bold))
                        .multilineTextAlignment(.center)
                        .foregroundColor(Color.gray)
                }
                .frame(width: 24, height: 24, alignment: .center)
                .cornerRadius(40)
                .overlay(
                    RoundedRectangle(cornerRadius: 40)
                        .inset(by: 0.5)
                        .stroke(Color.gray, lineWidth: 1)
                )

                Text(title)
                    .font(Font.custom("Inter", size: 16).weight(.bold))
                    .foregroundColor(Color.black)
            }
            Spacer()
//            Image(systemName: "chevron.down")
//                .rotationEffect(.degrees(isExpanded ? 180 : 0))
//                .foregroundColor(.primary)
//                .frame(width: 24, height: 24, alignment: .center)
        }
    }
}
1

There are 1 answers

2
flanker On

The chevron, like most system controls, will adopt the tint colour. You can't alter the opacity afaik, but you can darken it by changing the tint colour.

To force it to black you can do:

  DisclosureGroup(...)
         .tint(.black)

You can also apply it to the whole view hierarchy to set it for all items at once.

If this isn't sufficient you'll need to create your own custom version of the DisclosureGroup by using a custom DisclosuregroupStyle and applying it to the view hierarchy. Using SF Symbols for the chevron will then allow you full font control over its presentation, so you can make it as large, bold or opaque as your design requires. This will also allow you to condense all your modifiers into one place.

struct AccordionDisclosureStyle: DisclosureGroupStyle {
   func makeBody(configuration: Configuration) -> some View {
      VStack(alignment: .leading) {
         Button {
            configuration.isExpanded.toggle()
         } label: {
            HStack(alignment: .firstTextBaseline) {
               configuration.label
               Image(systemName: configuration.isExpanded ? "chevron.down" : "chevron.right")
                  .foregroundColor(.black)
                  .font(.body)
                  .frame(maxWidth: .infinity, alignment: .trailing)
                  .animation(nil, value: configuration.isExpanded)
            }
            .contentShape(Rectangle())
         }
         if configuration.isExpanded {
            configuration.content
               .padding(.leading, 40)
         }
      }
      .padding(16)
      .background(Color.white)

   }
}

You may want to play with the animation to get your desired effect.

You can then apply to your whole view hierarchy and it will configure all the disclosure groups.

struct ContentView: View {
   @State private var isExpanded1 = false
   @State private var isExpanded2 = false
   @State private var isExpanded3 = false
   @State private var isExpanded4 = false
   
   var body: some View {
      List {
            // Accordion Section 1
         DisclosureGroup(...)
            // Accordion Section 2
         DisclosureGroup(...)
            // Accordion Section 3
         DisclosureGroup(...)
         
            // Accordion Section 4
         DisclosureGroup(...)
      }
      .disclosureGroupStyle(AccordionDisclosureStyle())
   }   

In the example note that the VStack has been replaced with a List as this provides a far better animation when the group is expanded (this also requires your frame modifier to be removed).

[Also, as an aside, look to create an array containing the content for each group and iterate through that, rather than writing each entry out in ints entirety]