简体   繁体   English

SwiftUI - 当数据源为空时,动态列表过滤 animation 飞到右侧

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

I have a List that gets data from my people array and displays their names.我有一个List ,它从我的people数组中获取数据并显示他们的姓名。

I'm also filtering the list so that it only shows the names that contain the text field's text, which is searchText .我还在过滤列表,使其仅显示包含文本字段文本的名称,即searchText Here's my code:这是我的代码:

struct Person: Identifiable {
    let id = UUID() /// required for the List
    
    var name = ""
}

struct ContentView: View {
    
    @State var searchText = ""
    
    var people = [ /// the data source
        Person(name: "Alex"),
        Person(name: "Ally"),
        Person(name: "Allie"),
        Person(name: "Bob"),
        Person(name: "Tim"),
        Person(name: "Timothy")
    ]
    
    var body: some View {
        
        VStack {
            TextField("Search here", text: $searchText) /// text field
            .padding()
            
            List {
                ForEach(
                    people.filter { person in /// filter the people
                        searchText.isEmpty || person.name.localizedStandardContains(searchText)
                    }
                ) { person in
                    Text(person.name)
                }
            }
            .animation(.default) /// add the animation
        }
    }
}

Without .animation(.default) , it doesn't animate the changes (as expected).如果没有.animation(.default) ,它不会为更改设置动画(如预期的那样)。

无动画过滤

With .animation(.default) , it animates!使用.animation(.default) ,它会动画!

用动画过滤

However, the problem happens when none of the people's names contain searchText .但是,当人名都不包含searchText时,就会出现问题。 When this happens, the people.filter returns an empty array, and the List freaks out.发生这种情况时, people.filter返回一个空数组, List就会崩溃。 For example, when I type "q", this happens:例如,当我输入“q”时,会发生这种情况:

列表向右缩放

The entire list flies to the right, and zooms back in from the left when I delete "q".整个列表飞到右边,当我删除“q”时从左边放大。 How can I prevent this from happening?我怎样才能防止这种情况发生? I'm looking for a similar animation to the normal filtering animation (sliding up and disappearing, like in the second gif), or just fading it out.我正在寻找与正常过滤 animation 类似的 animation(向上滑动并消失,就像在第二个 gif 中一样),或者只是淡出它。

Edit: iOS 13编辑:iOS 13

I just tested on iOS 13 and if I remove .animation(.default) , it works perfectly!我刚刚在 iOS 13 上进行了测试,如果我删除.animation(.default) ,它可以完美运行!

iOS 13 上所需的动画

However, if I add .animation(.default) again, I get the same result as in iOS 14.但是,如果我再次添加.animation(.default) ,我会得到与 iOS 14 中相同的结果。

与 iOS 14 相同的结果

Edit: List with sections + @mahan 's answer编辑:列出部分 + @mahan的答案

My actual code groups the people, so I already use sections in my List .我的实际代码对人员进行了分组,因此我已经使用了List中的sections

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 = ""

    /// groups of people
    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 people that match searchText
                    groups.filter { group in
                        searchText.isEmpty || group.people.contains(where: { person in
                            person.name.localizedStandardContains(searchText)
                        })
                    }
                ) { group in
                    Section(header: Text(group.groupName)) {
                        ForEach(

                            /// filter the people in each group
                            group.people.filter { person in
                                searchText.isEmpty || person.name.localizedStandardContains(searchText)
                            }
                        ) { person in
                            Text(person.name)
                        }
                    }
                }
                
            }
            .animation(.default) /// add the animation
        }
    }
}

带部分的排序列表

If I wrap the ForEach inside the List as @mahan suggested, this happens:如果我按照@mahan 的建议将ForEach包装在List中,则会发生这种情况:

The List animates perfectly with no weird zoom animation, but the section headers lose their styles and look like normal rows. List动画完美,没有奇怪的缩放 animation,但节标题失去了 styles 并且看起来像正常行。 But I think we're getting close!但我认为我们正在接近!

Wrap ForEach in a Section , and the issue will be fixed.ForEach包装在Section中,问题将得到解决。

        List {
            Section {
                ForEach(
                    people.filter { person in /// filter the people
                        searchText.isEmpty || person.name.localizedStandardContains(searchText)
                    }
                ) { person in
                    Text(person.name)
                }
            }
        }
        .animation(.default) /// add the animation

Update更新

You can add as many sections as you wish so.您可以根据需要添加任意数量的部分。

struct Person: Identifiable {
    let id = UUID() /// required for the List
    
    var name = ""
}

struct ContentView: View {
    
    @State var searchText = ""
    
    var people = [ /// the data source
        Person(name: "Alex"),
        Person(name: "Ally"),
        Person(name: "Allie"),
        Person(name: "Bob"),
        Person(name: "Tim"),
        Person(name: "Timothy")
    ]
    
    var people2 = [ /// the data source
        Person(name: "John"),
        Person(name: "George"),
        Person(name: "Jack"),
        Person(name: "Mike"),
        Person(name: "Barak"),
        Person(name: "Steve")
    ]
    
    var body: some View {
        
        VStack {
            TextField("Search here", text: $searchText) /// text field
                .padding()
            
            List {
                Section {
                    ForEach(
                        people.filter { person in /// filter the people
                            searchText.isEmpty || person.name.localizedStandardContains(searchText)
                        }
                    ) { person in
                        Text(person.name)
                    }
                }
                
                Section {
                    ForEach(people2.filter { person in /// filter the people
                        searchText.isEmpty || person.name.localizedStandardContains(searchText)
                    }) { person in
                        Text(person.name)
                    }
                }
            }
            .animation(.default) /// add the animation
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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