简体   繁体   中英

SwiftUI - Prevent Sections from flying/zooming to the right in List when dynamically filtering them

I originally asked this question:

SwiftUI - Dynamic List filtering animation flies to right side when data source is empty

There, I had a List without sections. I was filtering them so that it only showed the rows that contained the text inside a TextField . The solution was to wrap everything inside the List in a Section .

Unfortunately, I now need to filter Section s. Here's my code:

struct Group: Identifiable {
    let id = UUID() /// required for the List
    
    var groupName = ""
    var people = [Person]()
}
struct Person: Identifiable {
    let id = UUID() /// required for the List
    
    var name = ""
}
struct ContentView: View {

    @State var searchText = ""

    var groups = [
        Group(groupName: "A People", people: [
            Person(name: "Alex"),
            Person(name: "Ally"),
            Person(name: "Allie")
        ]),
        Group(groupName: "B People", people: [
            Person(name: "Bob")
        ]),
        Group(groupName: "T People", people: [
            Person(name: "Tim"),
            Person(name: "Timothy")
        ])
    ]

    var body: some View {

        VStack {
            TextField("Search here", text: $searchText) /// text field
                .padding()
            
            List {
                ForEach(
                    
                    /// Filter the groups for those that contain searchText
                    groups.filter { group in
                        searchText.isEmpty || group.groupName.localizedStandardContains(searchText)
                    }
                    
                ) { group in
                    Section(header: Text(group.groupName)) {
                        ForEach(group.people) { person in
                            Text(person.name)
                        }
                    }
                    
                }
            }
            .animation(.default) /// apply the animation
        }
    }
}

Result:

过滤部分使它们飞走

I pass in a filtered array in the ForEach to determine the Section s. However, whenever that array changes, the List animates really weirdly. The Section s zoom/fly to the right side, and come back from the left when the array includes them again. How can I avoid this animation?

If I remove .animation(.default) , it doesn't animate at all, as expected. But, I would still like an animation . Is there a way to fade the changes, or slide them instead?

The solution is not using List. As long as you're not using selection and row deleting a ScrollView is basically the same.

If you want to style it a bit like the List that's also not that hard:

struct SearchAnimationExample: View {

    ...

    var body: some View {

        VStack {
            TextField("Search here", text: $searchText) /// text field
                .padding()
            
            ScrollView {
                VStack(spacing: 0) {
                    ForEach(
                        groups.filter { group in
                            searchText.isEmpty || group.groupName.localizedStandardContains(searchText)
                        }
                    ) { group in
                        Section(header: header(title: group.groupName)) {
                            ForEach(group.people) { person in
                                row(for: person)
                                Divider()
                            }
                        }
                        
                    }.transition(.opacity) // Set which transition you would like
                    
                    // Always full width
                    HStack { Spacer() }
                }
            }
            .animation(.default) 
        }
    }
    
    func header(title: String) -> some View {
        HStack {
            Text(title).font(.headline)
            Spacer()
        }
        .padding(.horizontal)
        .background(Color.gray.opacity(0.4))
    }
        
    func row(for person: Person) -> some View {
        HStack {
            Text(person.name)
            Spacer()
        }.padding()
    }
}

Looks practically the same as the default list:

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM