SwiftUI - 动态列表过滤动画在数据源为空时飞到右侧
SwiftUI - Dynamic List filtering animation flies to right side when data source is empty
我有一个 List
从我的 people
数组中获取数据并显示他们的名字。
我还在过滤列表,以便它只显示包含文本字段文本的名称,即 searchText
。这是我的代码:
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
}
}
}
如果没有 .animation(.default)
,它不会对变化进行动画处理(如预期的那样)。
有了 .animation(.default)
,它就动起来了!
但是,当 none 的人名中包含 searchText
时,就会出现问题。发生这种情况时,people.filter
returns 是一个空数组,而 List
会崩溃。例如,当我键入“q”时,会发生这种情况:
整个列表向右飞,当我删除“q”时从左边放大。 如何防止这种情况发生? 我正在寻找与正常过滤动画类似的动画(向上滑动并消失,就像在第二个 gif 中一样),或者只是淡出。
编辑:iOS 13
我刚刚在 iOS 13 上进行了测试,如果我删除 .animation(.default)
,它会完美运行!
但是,如果我再次添加 .animation(.default)
,我会得到与 iOS 14.
相同的结果
编辑:包含部分的列表 + @mahan 的回答
我的实际代码将人分组,所以我已经在我的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
}
}
}
如果我按照@mahan 的建议将 ForEach
包裹在 List
中,则会发生这种情况:
List
动画完美,没有奇怪的缩放动画,但 headers 部分失去了它们的样式,看起来像普通行。但我认为我们越来越接近了!
将 ForEach 包装在 部分 中,问题将得到解决。
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
更新
您可以根据需要添加任意数量的部分。
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
}
}
}
我有一个 List
从我的 people
数组中获取数据并显示他们的名字。
我还在过滤列表,以便它只显示包含文本字段文本的名称,即 searchText
。这是我的代码:
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
}
}
}
如果没有 .animation(.default)
,它不会对变化进行动画处理(如预期的那样)。
有了 .animation(.default)
,它就动起来了!
但是,当 none 的人名中包含 searchText
时,就会出现问题。发生这种情况时,people.filter
returns 是一个空数组,而 List
会崩溃。例如,当我键入“q”时,会发生这种情况:
整个列表向右飞,当我删除“q”时从左边放大。 如何防止这种情况发生? 我正在寻找与正常过滤动画类似的动画(向上滑动并消失,就像在第二个 gif 中一样),或者只是淡出。
编辑:iOS 13
我刚刚在 iOS 13 上进行了测试,如果我删除 .animation(.default)
,它会完美运行!
但是,如果我再次添加 .animation(.default)
,我会得到与 iOS 14.
编辑:包含部分的列表 + @mahan 的回答
我的实际代码将人分组,所以我已经在我的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
}
}
}
如果我按照@mahan 的建议将 ForEach
包裹在 List
中,则会发生这种情况:
List
动画完美,没有奇怪的缩放动画,但 headers 部分失去了它们的样式,看起来像普通行。但我认为我们越来越接近了!
将 ForEach 包装在 部分 中,问题将得到解决。
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
更新
您可以根据需要添加任意数量的部分。
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
}
}
}