问题描述
我有一个 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 - 当数据源为空时,动态列表过滤动画飞到右侧的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!