macOS 上的 SwiftUI:如何启用 onDelete UI(从列表中删除)

问题描述 投票:0回答:4

也许我今天早上特别密集,但我正在尝试从 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 swiftui
4个回答
19
投票

对于 macOS,我们使用右键单击并查看“删除”等菜单选项。您可以将上下文菜单添加到列表中,例如

List(selection: $selection) {
    ForEach(items, id: \.self) { item in
        Text(item)
            .contextMenu {
                Button(action: {
                    // delete item in items array
                }){
                    Text("Delete")
                }
            }
    }

}


13
投票

此代码启用“删除”菜单,并在我选择“编辑”>“删除”时删除所选项目(无需手动连接菜单):

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 - 选择“编辑”>“删除” - 单击“等效密钥”字段 - 按删除键。

enter image description here

运行应用程序,选择一个项目,按删除键,您的项目就会消失。


2
投票

我面临同样的问题,我发现两根手指滑动会触发删除。由于我删除了

onDelete()
中的元素,它因致命错误而崩溃,而且我仍在弄清楚如何修复它:

索引超出范围

编辑:我将索引替换为元素,它工作正常。

ForEach(elementArray.indices) { index in 
    // code... 
}

ForEach(elementArray) { element in 
    // code... 
}

而且效果很好:)


1
投票

我找到了一个相当复杂的解决方案,我希望有更好的方法。

我所做的如下:

  • 将操作连接到现有的“删除”命令
  • 创建一个“ObservableObject”
    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

© www.soinside.com 2019 - 2024. All rights reserved.