ray*_*ayx 5 list swipe ios swiftui
可以使用下面的代码一致地重现该问题。Xcode 13.3 + iOS 15.4(都是最新的)。
enum ListID: String, CaseIterable, Hashable, Identifiable {
case list1 = "List1"
case list2 = "List2"
var id: Self {
self
}
}
struct ContentView: View {
@State var listID: ListID = .list1
var body: some View {
VStack {
// 1) Picker
Picker(selection: $listID) {
ForEach(ListID.allCases) { id in
Text(id.rawValue)
}
} label: {
Text("Select a list")
}
.pickerStyle(.segmented)
// 2) List
switch listID {
case .list1:
createList(Array(1...2), id: .list1)
case .list2:
createList(Array(101...102), id: .list2)
}
}
}
@ViewBuilder func createList(_ itemValues: [Int], id: ListID) -> some View {
List {
ForEach(itemValues, id:\.self) { value in
Text("\(value)")
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
Button("Edit") {
// do nothing
}
.tint(.blue)
}
}
}
.id(id)
}
}
Run Code Online (Sandbox Code Playgroud)
重现问题的步骤:
该问题并非特定于选择器。例如,如果我们用一组按钮替换选择器,就可以重现它。我相信只有当旧列表在 SwiftUI 视图层次结构中被销毁时才会出现此问题。根据我对 SwiftUI 中结构化身份的理解,列表 1 和列表 2 被视为 SwiftUI 视图层次结构中的单独视图。因此尚不清楚它们如何相互影响。我能猜测的唯一原因是,虽然列表 1 和列表 2 被视为单独的虚拟视图,但 SwiftUI 实际上为它们使用相同的物理视图(例如,出于性能目的等)。所以对我来说这似乎是一个 SwiftUI 错误。
沿着这条线思考,我可以通过不破坏列表来解决这个问题:
ZStack {
createList(Array(1...2), id: .list1)
.opacity(listID == .list1 ? 1 : 0)
createList(Array(101...102), id: .list2)
.opacity(listID == .list2 ? 1 : 0)
}
Run Code Online (Sandbox Code Playgroud)
这在这个特定示例中完美运行,但不幸的是它不可扩展。例如,在我的日历应用程序中,当用户单击日历中的日期时,我想显示该日期的事件列表(我想对不同的日期使用不同的列表。我通过调用来id()设置每个列表都有不同的 ID)。在这种情况下,没有明显/优雅的方法来应用上述解决方案。
所以我想知道是否有人知道如何以更通用的方式解决这个问题?谢谢。
我最终通过对不同列表使用单个虚拟视图来解决这个问题。为此,我需要将 List 移到switch语句之外(否则 SwiftUI 的结构化身份机制会将这两个列表视为不同的列表)。
该解决方法在我的测试中可靠地工作(包括在我的实际应用程序中进行测试)。它很干净而且一般。我更喜欢为每个列表分配不同的 id,因为我认为它在架构上更干净且更好,但不幸的是,在 Apple 修复该错误之前它无法使用。我已经提交了关于这个问题的FB9976079。
我将保持我的问题开放,并欢迎任何人留下您的答案或评论。
enum ListID: String, CaseIterable, Hashable, Identifiable {
case list1 = "List1"
case list2 = "List2"
var id: Self {
self
}
}
struct ContentView: View {
@State var listID: ListID = .list1
var body: some View {
VStack {
// 1) Picker
Picker(selection: $listID) {
ForEach(ListID.allCases) { id in
Text(id.rawValue)
}
} label: {
Text("Select a list")
}
.pickerStyle(.segmented)
// 2) List
List {
switch listID {
case .list1:
createSection(Array(1...2), id: .list1)
case .list2:
createSection(Array(101...105), id: .list2)
}
}
}
}
// Note: the id param is not used as List id.
@ViewBuilder func createSection(_ itemValues: [Int], id: ListID) -> some View {
Section {
ForEach(itemValues, id:\.self) { value in
Text("\(value)")
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
Button("Edit") {
// do nothing
}
.tint(.blue)
}
}
}
.id(id)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
608 次 |
| 最近记录: |