SwiftUI - 当数据源为空时,动态列表过滤动画飞到右侧 [英] SwiftUI - Dynamic List filtering animation flies to right side when data source is empty

查看:17
本文介绍了SwiftUI - 当数据源为空时,动态列表过滤动画飞到右侧的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 List 从我的 people 数组中获取数据并显示他们的名字.

我还过滤了列表,以便它只显示包含文本字段文本的名称,即 searchText.这是我的代码:

struct Person: Identifiable {let id = UUID()///需要列表var name = "";}结构内容视图:查看{@State var searchText = "";var people = [///数据源人(姓名:亚历克斯"),人(姓名:盟友"),人(姓名:艾莉"),人(姓名:鲍勃"),人(姓名:蒂姆"),人(姓名:蒂莫西")]var主体:一些视图{虚拟堆栈{TextField("Search here", text: $searchText)///文本字段.填充()列表 {ForEach(people.filter { person in///过滤人searchText.isEmpty ||person.name.localizedStandardContains(searchText)}) { 人在文本(人名)}}.animation(.default)///添加动画}}}

如果没有 .animation(.default),它不会对更改进行动画处理(如预期).

使用 .animation(.default),它会产生动画效果!

然而,当没有人的名字包含searchText 时,问题就会发生.发生这种情况时,people.filter 返回一个空数组,List 会崩溃.例如,当我输入q"时,会发生这种情况:

整个列表向右飞,并在我删除q"时从左侧放大.如何防止这种情况发生?我正在寻找与正常过滤动画类似的动画(向上滑动和消失,就像在第二个 gif 中一样),或者只是淡出它.

iOS 13

我刚刚在 iOS 13 上进行了测试,如果我删除了 .animation(.default),它可以完美运行!

但是,如果我再次添加 .animation(.default),我会得到与 iOS 14 相同的结果.

部分列表 +

如果我按照@mahan 的建议将 ForEach 包装在 List 中,就会发生这种情况:

List 动画完美,没有奇怪的缩放动画,但部分标题失去了它们的样式,看起来像正常的行.但我认为我们正在接近!

解决方案

ForEach 包裹在 Section 中,问题将得到解决.

 列表 {部分 {ForEach(people.filter { person in///过滤人searchText.isEmpty ||person.name.localizedStandardContains(searchText)}) { 人在文本(人名)}}}.animation(.default)///添加动画


更新

您可以添加任意数量的部分.

struct Person: Identifiable {let id = UUID()///需要列表var name = "";}结构内容视图:查看{@State var searchText = "";var people = [///数据源人(姓名:亚历克斯"),人(姓名:盟友"),人(姓名:艾莉"),人(姓名:鲍勃"),人(姓名:蒂姆"),人(姓名:蒂莫西")]var people2 = [///数据源人(姓名:约翰"),人(姓名:乔治"),人(姓名:杰克"),人(姓名:迈克"),人(姓名:巴拉克"),人(姓名:史蒂夫")]var主体:一些视图{虚拟堆栈{TextField("Search here", text: $searchText)///文本字段.填充()列表 {部分 {ForEach(people.filter { person in///过滤人searchText.isEmpty ||person.name.localizedStandardContains(searchText)}) { 人在文本(人名)}}部分 {ForEach(people2.filter { person in///过滤人searchText.isEmpty ||person.name.localizedStandardContains(searchText)}) { 人在文本(人名)}}}.animation(.default)///添加动画}}}

I have a List that gets data from my people array and displays their names.

I'm also filtering the list so that it only shows the names that contain the text field's text, which is 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).

With .animation(.default), it animates!

However, the problem happens when none of the people's names contain searchText. When this happens, the people.filter returns an empty array, and the List freaks out. For example, when I type "q", this happens:

The entire list flies to the right, and zooms back in from the left when I delete "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.

Edit: iOS 13

I just tested on iOS 13 and if I remove .animation(.default), it works perfectly!

However, if I add .animation(.default) again, I get the same result as in iOS 14.

Edit: List with sections + @mahan's answer

My actual code groups the people, so I already use sections in my List.

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:

The List animates perfectly with no weird zoom animation, but the section headers lose their styles and look like normal rows. But I think we're getting close!

解决方案

Wrap ForEach in a Section, and the issue will be fixed.

        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
        }
    }
}

这篇关于SwiftUI - 当数据源为空时,动态列表过滤动画飞到右侧的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆