I am trying to build a macOS (14.6) app that uses a combination of List(_:selection:rowContent:) and Section(isExpanded:content:header:), and while it “works”, it looks like garbage. When using .plain, there are list row/section seperators, and even when using .listRowSeparator(.hidden) or .listSectionSeparator(.hidden), there is always one separator that is still visible between the first item and the remaining items.

When I try to use .listStyle(.sidebar), it adds its own disclosure indicator, but on the right side of the list row. It’s tolerable, though I’d prefer the indicator on the left and not to auto-hide when not being hovered.

The kicker is that regardless of the .listStyle() used, there seems to be spacing/padding between the sections that cannot be removed. In Apple’s infinite wisdom, they added .listRowSpacing(), but decided macOS shouldn’t get to use it.

I am still new to all of this, and would really appreciate any advice on how I can style my UI the way I need it to be. I am using SwiftUI, but if there is another method (maybe UIKit or somthing?), I’m open to suggestion.

Here is my playground code used to generate the screenshots:

import SwiftUI
import PlaygroundSupport

struct Content: Hashable, Identifiable {
    var id: Self { self }
    var header: String
    var contents: [String]
}

struct ContentView: View {
    var contents: [Content] = [
        Content(header: "My Section 1", contents: ["Hello", "world"]),
        Content(header: "My Section 2", contents: ["Foo", "bar"]),
        Content(header: "My Section 3", contents: ["Help", "Me"]),
    ]

    @State private var expanded: Set<Content> = []
    @State private var selected: String?

    var body: some View {
        NavigationSplitView {
            List(contents, selection: $selected) { content in
                Section(isExpanded: Binding<Bool>(
                    get: { return expanded.contains(content) },
                    set: { expanding in
                        if expanding {
                            expanded.insert(content)
                        } else {
                            expanded.remove(content)
                        }
                    }
                ), content: {
                    ForEach(content.contents, id: \.self) { data in
                        Text(data)
                            .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
                            .border(Color.orange)
                    }
                }, header: {
                    Text(content.header)
                        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
                        .onTapGesture {
                            if expanded.contains(content) {
                                expanded.remove(content)
                            } else {
                                expanded.insert(content)
                            }
                        }
                })
                .listRowInsets(EdgeInsets(
                    top: 0,
                    leading: -2,
                    bottom: 0,
                    trailing: -14
                ))
            }
        } detail: {
            ContentUnavailableView {
                Label("No selection made", systemImage: "tray")
            }
        }
        .border(Color.gray)
    }
}

// Present the view in Playground
PlaygroundPage.current.setLiveView(ContentView())

Edit: 3 hours later… I was able to remove the spacing from the section content’s items by using listRowInsets(_ insets:) and removing some of the padding I put in the code. But, I still do not know how to affect the section headers. I’ve updated the code above, and here’s a new screenshot:

  • chonkyninja@lemmy.world
    link
    fedilink
    English
    arrow-up
    1
    ·
    1 month ago

    Why aren’t you just using a Disclosure group? Also whatever it is you are trying to expand, why do you need to hide content in a non-standard way?

    • dohpaz42@lemmy.worldOP
      link
      fedilink
      English
      arrow-up
      1
      ·
      1 month ago

      I can answer both your questions: because I don’t know what I don’t know.

      I will look up disclosure group; I’d love to hear more about a better, more standard way to do collapsible menus (maybe I’m calling them the wrong thing).

  • chonkyninja@lemmy.world
    link
    fedilink
    English
    arrow-up
    1
    ·
    1 month ago

    More criticism, the selected variable. List selection by default uses Identity, but you thought, hey I’ll just use a string?

    Your expanded variable, the fucking fuck? Please go back and read the documented walk-thru’s.

    • dohpaz42@lemmy.worldOP
      link
      fedilink
      English
      arrow-up
      1
      ·
      1 month ago

      Counter criticism: this is a playground where I was trying to keep it simple to focus on the problem at hand.

      The expanded variable was something I found in a walk through online, so if there’s a better way, I’m all eyes.

      Be nice, as I’ve said before, I’m new at this.