Swiftui 2.0 List with Children - How to Make the Tappable Area of the Disclosure Button Cover the Whole List Item

SwiftUI 2.0 List with children - how to make the tappable area of the disclosure button cover the whole list item

Here is a demo of approach (of course in your project you'd move expand/collapse state into view model)

demo

struct DemoDisclosureGroups: View {
let items: [Bookmark] = [.example1, .example2, .example3]
@State private var flags: [Bool] = [false, false, false]

var body: some View {
List {
ForEach(Array(items.enumerated()), id: \.1.id) { i, group in
DisclosureGroup(isExpanded: $flags[i]) {
ForEach(group.items ?? []) { item in
Label(item.name, systemImage: item.icon)
}
} label: {
Label(group.name, systemImage: group.icon)
.contentShape(Rectangle())
.onTapGesture {
withAnimation {
self.flags[i].toggle()
}
}
}
}
}
}
}

struct Bookmark: Identifiable {
let id = UUID()
let name: String
let icon: String
var items: [Bookmark]?

// some example websites
static let apple = Bookmark(name: "Apple", icon: "1.circle")
static let bbc = Bookmark(name: "BBC", icon: "square.and.pencil")
static let swift = Bookmark(name: "Swift", icon: "bolt.fill")
static let twitter = Bookmark(name: "Twitter", icon: "mic")

// some example groups
static let example1 = Bookmark(name: "Favorites", icon: "star", items: [Bookmark.apple, Bookmark.bbc, Bookmark.swift, Bookmark.twitter])
static let example2 = Bookmark(name: "Recent", icon: "timer", items: [Bookmark.apple, Bookmark.bbc, Bookmark.swift, Bookmark.twitter])
static let example3 = Bookmark(name: "Recommended", icon: "hand.thumbsup", items: [Bookmark.apple, Bookmark.bbc, Bookmark.swift, Bookmark.twitter])
}

SwiftUI (2.0) list with children crashes when trying to delete the last element

I seem to have been able to figure this out myself after a little more probing around. The out-of-range error occurred on this line:

DisclosureGroup(isExpanded: $goodies.users[i].isExpanded) {

(I was able to tell by replacing with .constant(true) which stopped the crash.)

I was able to fix this by using a function that gives a custom binding given the index i, which checks that the index is in range before accessing it:

func binding(for index: Int) -> Binding<Bool> {
Binding<Bool>(
get: {
if index > goodies.users.count - 1{
return false
}
return goodies.users[index].isExpanded
},
set: {
if index > goodies.users.count - 1 {
// do nothing
} else {
goodies.users[index].isExpanded = $0
}
}
)
}

Usage for the affected line:

DisclosureGroup(isExpanded: binding(for: i)) {

This fixes the crashing issue. It was a little hard to pinpoint before because I didn't realise the binding was accessed after the list item was removed. Hope this helps someone in the same position.

What are the requirements for a free expandable List in SwiftUI?

It is activated by sidebar list style (which in some conditions are considered as default), which you can use explicitly

List {
ForEach(userData.groupedBookings) { group in
Section(header: Text(group.key)) {
ForEach(group.items) { booking in
LessonRow(booking: booking)
}
}
}
}
.listStyle(SidebarListStyle())

as alternate you can use DisclosureGroup explicitly to have disclosure behavior for sections, like in https://stackoverflow.com/a/63228810/12299030



Related Topics



Leave a reply



Submit