也许我今天早上特别密集,但我正在尝试从 macOS 上的 SwiftUI 中的
List
中删除一行。
问题是没有公开的 UI 来执行删除。我的意思是,
List
不会响应删除按键,没有右键菜单,也不支持任何其他手势,例如滑动删除(无论如何,这在 macOS 上会很奇怪)。
这是我正在使用的示例:
import SwiftUI
struct ContentView: View {
@State var items = ["foo", "bar", "baz"]
@State var selection: String? = nil
var body: some View {
List(selection: $selection) {
ForEach(items, id: \.self) { Text($0) }
.onDelete { self.items.remove(atOffsets: $0)}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
iOS 上完全相同的代码为我提供了一个带有标准“向左滑动删除”UI 的表格视图。在 macOS 上什么也没有。
我尝试添加
.onDeleteCommand(perform: {
if let sel = self.selection, let idx = self.items.firstIndex(of: sel) {
self.items.remove(at: idx)
}
})
到
List
,但按删除键仍然没有反应。
如何在 macOS 上启用
List
行删除?
对于 macOS,我们使用右键单击并查看“删除”等菜单选项。您可以将上下文菜单添加到列表中,例如
List(selection: $selection) {
ForEach(items, id: \.self) { item in
Text(item)
.contextMenu {
Button(action: {
// delete item in items array
}){
Text("Delete")
}
}
}
}
此代码启用“删除”菜单,并在我选择“编辑”>“删除”时删除所选项目(无需手动连接菜单):
struct ContentView: View {
@State var items = ["foo", "bar", "baz"]
@State var selection: String? = nil
var body: some View {
List(selection: $selection) {
ForEach(items, id: \.self) { Text($0) }
}
.onDeleteCommand {
if
let sel = self.selection,
let idx = self.items.firstIndex(of: sel) {
print("delete item: \(sel)")
self.items.remove(at: idx)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.animation(.default)
}
}
然后,要使删除键起作用,请将其设为与删除菜单选项等效的键盘: - 编辑Main.storyboard - 选择“编辑”>“删除” - 单击“等效密钥”字段 - 按删除键。
运行应用程序,选择一个项目,按删除键,您的项目就会消失。
我面临同样的问题,我发现两根手指滑动会触发删除。由于我删除了
onDelete()
中的元素,它因致命错误而崩溃,而且我仍在弄清楚如何修复它:
索引超出范围
编辑:我将索引替换为元素,它工作正常。
ForEach(elementArray.indices) { index in
// code...
}
到
ForEach(elementArray) { element in
// code...
}
而且效果很好:)
我找到了一个相当复杂的解决方案,我希望有更好的方法。
我所做的如下:
Menu
,发布选定的菜单命令ContentView
,以便它可以订阅并对更改采取行动这是两个相关文件:
首先,
AppDelegate.swift
:
enum MenuCommand {
case none
case delete
}
class Menu: ObservableObject {
@Published var item: MenuCommand = .none
}
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var window: NSWindow!
@ObservedObject var menu = Menu()
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Create the SwiftUI view that provides the window contents.
let contentView = ContentView(menu: menu)
// Create the window and set the content view.
window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered, defer: false)
window.center()
window.setFrameAutosaveName("Main Window")
window.contentView = NSHostingView(rootView: contentView)
window.makeKeyAndOrderFront(nil)
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
@IBAction func delete(_ sender: Any) {
print("delete menu")
menu.item = .delete
}
}
和
ContentView.swift
:
import SwiftUI
struct ContentView: View {
@ObservedObject var menu: Menu
@State var items = ["foo", "bar", "baz"]
@State var selection: String? = nil
var body: some View {
List(selection: $selection) {
ForEach(items, id: \.self) { Text($0) }
}
.onReceive(
self.menu.objectWillChange
.receive(on: RunLoop.main)) { _ in
if
case .delete = self.menu.item,
let sel = self.selection,
let idx = self.items.firstIndex(of: sel) {
print("delete item: \(sel)")
self.items.remove(at: idx)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.animation(.default)
}
}
注意:不要忘记将“删除”菜单项连接到
IBAction
。