macOS 上的 SwiftUI:如何为 onDelete 启用 UI(从列表中删除)
Posted
技术标签:
【中文标题】macOS 上的 SwiftUI:如何为 onDelete 启用 UI(从列表中删除)【英文标题】:SwiftUI on macOS: How to enable UI for onDelete (deletion from List) 【发布时间】:2020-01-16 08:05:54 【问题描述】:也许我今天早上特别密集,但我试图在 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
行删除?
【问题讨论】:
我假设您必须明确添加编辑模式或向左侧滑动列表行。 嗯,我试过刷卡并添加.environment(\.editMode, .constant(.active))
给我'editMode' is unavailable in macOS
是的,只需检查没有 EditMode,但滑动即可工作 - 右侧显示红色删除按钮,点击删除记录。
哦,我明白了。我正在拖动鼠标以模拟滑动,但神奇的鼠标手势有效。必须有一种方法可以让退格起作用吗?我本来希望这是默认设置。
【参考方案1】:
此代码启用“删除”菜单并在我选择“编辑”>“删除”时删除所选项目(无需手动连接菜单):
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 - 选择编辑 > 删除 - 单击“等效密钥”字段 - 点击删除键。
运行应用程序,选择一个项目,按删除键,您的项目应该会消失。
【讨论】:
这看起来等同于我最初的问题。这两个版本的行为对您来说是否不同? 嗯,我想我绕了一圈你的原始代码的变体......但是,刚刚编辑了我的答案以添加如何将删除键连接到删除菜单项。有了它,我可以单击一行并按下删除键,它就会删除。所以我想简短的回答是“将删除键添加为相当于 Menu.storyboard 中的编辑 > 删除菜单的键盘”,但我会将汇编代码保留在适当的位置以便于复制/粘贴。【参考方案2】:对于 macOS,我们使用右键单击并查看菜单选项,例如删除。您可以在列表中添加一个上下文菜单,例如
List(selection: $selection)
ForEach(items, id: \.self) item in
Text(item)
.contextMenu
Button(action:
// delete item in items array
)
Text("Delete")
【讨论】:
【参考方案3】:我找到了一个相当复杂的解决方案,我希望有更好的方法。
我所做的是:
将操作连接到现有的“删除”命令 创建发布选定菜单命令的“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
。
【讨论】:
【参考方案4】:我面临同样的问题,我发现两根手指滑动触发删除。自从我删除 onDelete()
中的元素后,它因致命错误而崩溃,我仍在想办法解决它:
索引超出范围
编辑:我将索引替换为元素,效果很好。
ForEach(elementArray.indices) index in
// code...
到
ForEach(elementArray) element in
// code...
而且效果很好:)
【讨论】:
以上是关于macOS 上的 SwiftUI:如何为 onDelete 启用 UI(从列表中删除)的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI 2.0 在 macOS 上禁用窗口的缩放按钮