SwiftUI中如何在iOS 15上同时使用editMode的onDelete修饰符和自定义Swipe Actions?

7

初始描述

我目前有一个动态列表,并使用SwiftUI内置的editMode功能和内置的EditButton(),以便让用户从列表中删除项目。

对于删除部分,我使用onDelete修饰符,它会添加红色滑动手势的后缀Delete,如您所知。

这是一个例子:

List {
    ForEach(someList) { someElement in
        Text(someElement.name)
    }
    .onDelete { (indexSet) in }
    .onMove { (source, destination) in }
}
.toolbar {
    ToolbarItem(placement: .navigationBarLeading) {
        EditButton()
    }
}
.environment(\.editMode, $editMode)

目标

现在我想要使用 iOS 15 的.swipeActions修饰符,以添加我们自己的自定义前导或后续滑动手势。

我希望用户也能通过向右滑动编辑列表元素,因此我为我的行添加了一个前导滑动操作:

Text(someElement.name)
.swipeActions(edge: .leading) {
    Button("Edit") { }
}

按钮的操作显然包含了允许编辑的代码。

问题

使用.swipeActions修饰符会破坏editMode的正常行为,特别是.onDelete修饰符。实际上,在这种设置下,我无法再向左滑动以删除行。

所以问题来了:如何在列表中同时使用SwiftUI editMode.onDelete修饰符和自定义的leading滑动操作?

最小可重现示例

Xcode Playground,适用于iOS 15。

import SwiftUI
import PlaygroundSupport

struct SomeList: Identifiable {
    let id: UUID = UUID()
    var name: String
}

let someList: [SomeList] = [
    SomeList(name: "row1"),
    SomeList(name: "row2"),
    SomeList(name: "row3")
]

struct ContentView: View {
    @State private var editMode = EditMode.inactive
    
    var body: some View {
        NavigationView {
            List {
                ForEach(someList) { someElement in
                    Text(someElement.name)
                    .swipeActions(edge: .leading) {
                        Button("Edit") { }
                    }
                }
                .onDelete { (indexSet) in }
                .onMove { (source, destination) in }
            }
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    EditButton()
                }
            }
            .environment(\.editMode, $editMode)
        }
    }
}

PlaygroundPage.current.setLiveView(ContentView())

你可以进行以下测试:如果你评论或删除这部分内容:
.swipeActions(edge: .leading) {
    Button("Edit") { }
}

然后重新应用.onDelete修改器即可正常工作。重新应用后使用.onDelete功能会出现问题。

额外信息

我正在为iOS 15构建此应用,因为我在使用.swipeActions修改器。

我愿意接受任何解决方案,以实现我的目标,即允许用户向左滑动以删除行,并向右滑动以触发任何编辑代码。即使这意味着使用另一种方式来使用.swipeActions修改器,或者使用SwiftUI editMode的另一种方式来使用.onDelete修改器,或两者兼而有之。

由于这个.swipeActions修改器,我只能为iOS 15构建应用程序,所以如果我可以为更低版本的iOS构建应用程序,那就更好了。

如果您需要任何其他信息,请告诉我。谢谢。


3
有时阅读文档会有帮助:swipeActions - "当你添加滑动操作时,SwiftUI不再合成Delete操作,否则在使用删除(perform:)方法的ForEach实例时会出现。如果适用,在你的滑动操作中创建一个Delete操作将由你负责。" - Yrb
事实上,我没有阅读文档的这一部分,但在测试时我注意到了这种行为。那么你对我的问题有什么建议?我应该停止使用滑动操作还是应该实现自己的删除操作? - AdamSwift
这是你的决定。如果你想使用.swipeActions(),你必须实现自己的.onDelete()操作。你不再免费获得它。 - Yrb
1
您可以在工具栏中添加另一个按钮。实际上,任何手势、按钮等都只是用户交互的一种方式。如果关闭了一条路径,就需要使用另一条路径。你甚至可以实现“摇晃编辑”,但这将是一种不寻常的用户界面。这真的偏离了UI意见领域。并且记住,您可以使用滑动操作,只需为删除操作添加一个操作即可。 - Yrb
1
您还可以在应用程序中测试iOS版本,并呈现代码集。但是,无论您是否可以使用.onDelete().swipeActions(),这始终是如此。一旦您将.swipeActions()放入您的代码中,它就只适用于iOS 15及以上版本。再次强调,这是开发者的选择。 - Yrb
显示剩余3条评论
1个回答

0

这是你想要的,用于删除特定行的代码。你可以在 swipeAction() 中使用它,也可以在 .onDelete() 中使用。

它允许你保持两者都可用。

func deleteSelectedItem(selectedItem: FetchedResults<Item>.Element) {
    viewContext.delete(selectedItem as NSManagedObject)
    saveCoreData()
}

就像这样使用它

ForEach(items) { item in
Text("").swipeActions() { Button { deleteSelectedItem(selectedItem: item) } }

这将删除触发滑动的项目。之后,您还可以在ForEach之外添加原始的onDelete()

 ForEach {    } .onDelete(perform: deleteItems)

这两个都能为你工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接