Issue with DisclosureGroup Animation Within SwiftUI ForEach Loop.

Description:

I have developed an app that allows users to create folders, and I'm utilizing the DisclosureGroup component for this functionality. While I am currently using Firebase, for the purpose of this demonstration, I have simplified the setup using a @State variable.

The issue I am encountering revolves around an unusual animation behavior during the entrance and deletion of the DisclosureGroup. It's worth noting that this behavior is specific to the DisclosureGroup component. I have experimented with other components, such as a VStack with text or a custom DisclosureGroup, and encountered no problems.

This problem emerged specifically with the release of iOS 17; there were no issues with iOS 16.

I would appreciate any insights or suggestions on resolving this animation behavior with the DisclosureGroup on iOS 17.

Thank you.

Video demonstration of the problem:

  • https://youtube.com/shorts/pkz3LMXhlsg

Code implementation

  • State Variable:
@State var testFolders: [Folder] = [
Folder(id: "1", nameFolder: "test1", noteFolder: "", timestamp: Date().timeIntervalSince1970), 
Folder(id: "2", nameFolder: "test2", noteFolder: "", timestamp: Date().timeIntervalSince1970 + 20000),]
  • Button to append a new folder:
  .toolbar{
        ToolbarItem{
            Button{
                 testFolders.append(Folder(id: "3", nameFolder: "test3", noteFolder: "", timestamp: Date().timeIntervalSince1970 + 500000))
             } label: {
                    Image(systemName: "folder.badge.plus")
               }
        } 
}
  • Displaying in a List:
List {
      Section {
          listFolders
     }
}
.listStyle(.plain)
.animation(.default, value: viewModel.folders)
.animation(.default, value: viewModel.plans)
private var listFolders: some View {
ForEach(testFolders.sorted(by: { $0.timestamp > $1.timestamp }), id: \.id) { folder in
            DisclosureGroup(isExpanded: Binding<Bool>(
                get: { viewModel.expanded.contains(folder.id) },
                set: { isExpanding in
                    if isExpanding {
                        viewModel.expanded.insert(folder.id)
                    } else {
                        viewModel.expanded.remove(folder.id)
                    }
                }
            )) {

            } label: {
                Text(folder.nameFolder)
                    .font(.headline)
                    .swipeActions {
                        Button {
                            viewModel.getFolderPlans(plans: viewModel.plans, folder: folder)
                            viewModel.folderToShowInfo = folder
                            viewModel.isShowingDetail = true
                        } label: {
                            Label("Edit", systemImage: "square.and.pencil")
                        }
                        .tint(Color.indigo)
                        
                        Button {
                            withAnimation{
                                _ = viewModel.expanded.remove(folder.id)
                            }
                            viewModel.folderToDelete = folder
                            viewModel.showDialog = true
                        } label: {
                            Label("Delete", systemImage: "trash.fill")
                        }
                        .tint(Color.red)
                    }
            }
            
        }

I personally don't like Swiftui at all. What ever you do, you'll get stuck at some point. When you want to implement/customise something, then it often ends up, "No you won't be able to do it in swifUI" kind of deadlock situation.

My personal opinion is, start using UIKit or Cocoa, you're very unlikely to get stuck in a deadlock situation with those.

I personally named "swiftUI" as "kidsUI" 😁

In my case my List has a mix of DiscloseGroup rows and normal rows. My rows each have a checkbox such that if you check a row off it moves the row to the bottom (.i.e re-sorts the list within a withAnimation block). I'm seeing the bad animation when two or more DisclosureGroups are adjacent in the List. If you check the top one, then in the re-order animation it moves the row underneath down to the bottom, instead of the row you tapped, and then updates the row content for each of those rows, the original position and new position, at the end of the animation.

If you try this when the DiscloseGroup is expanded it animates moving all the children but not the row itself.

If you try this with a normal (non-DisclosureGroup) row, or a DisclosureGroup row that doesn't have a DisclosureGroup right below it, it works fine.

I'm on iOS 17 as well.

Issue with DisclosureGroup Animation Within SwiftUI ForEach Loop.
 
 
Q