UndoManager 的 canUndo 属性 未在 SwiftUI 中更新
UndoManager's canUndo property not updating in SwiftUI
为什么 @Environment
UndoManager
在其堆栈中有操作时不更新其 canUndo
属性?我有一个视图有一个可以使用 un/redo 功能的子视图,但出于某种原因我无法禁用基于管理器的撤消按钮。
struct MyView: View {
@Environment(\.undoManager) var undoManager: UndoManager?
var body: some View {
Button("Undo") { ... }
.disabled(!self.undoManager!.canUndo)
}
}
UndoManager.canUndo
不符合 KVO,因此使用一些通知发布者来跟踪状态,如下所示
struct MyView: View {
@Environment(\.undoManager) var undoManager
@State private var canUndo = false
// consider also other similar notifications
private let undoObserver = NotificationCenter.default.publisher(for: .NSUndoManagerDidCloseUndoGroup)
var body: some View {
Button("Undo") { }
.disabled(!canUndo)
.onReceive(undoObserver) { _ in
self.canUndo = self.undoManager!.canUndo
}
}
}
当涉及到 canRedo
时,我尝试了多种方法,我最终得到的是这个 - 所以观察 viewModel
(或 document
或任何其他支持撤消的数据源) 并更新 canUndo
/canRedo
以响应它的变化:
struct MyView: View {
@ObservedObject var viewModel: ViewModel
@Environment(\.undoManager) private var undoManger: UndoManager!
@State private var canUndo = false
@State private var canRedo = false
var body: some View {
RootView()
.onReceive(viewModel.objectWillChange) { _ in
canUndo = undoManger.canUndo
canRedo = undoManger.canRedo
}
if canUndo {
Button(
action: { undoManger?.undo() },
label: { Text("Undo") }
)
}
if canRedo {
Button(
action: { undoManger?.redo() },
label: { Text("Redo") }
)
}
...
我还将它包装在一个 standalone button 中(没有过度概括超出我自己需要的实现),它从我的角度消除了样板文件并使复杂性更加私密,所以它最终对我来说是这样的:
struct MyView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
RootView()
UndoManagerActionButton(
.undo,
willChangePublisher: viewModel.objectWillChange
)
UndoManagerActionButton(
.redo,
willChangePublisher: viewModel.objectWillChange
)
...
为什么 @Environment
UndoManager
在其堆栈中有操作时不更新其 canUndo
属性?我有一个视图有一个可以使用 un/redo 功能的子视图,但出于某种原因我无法禁用基于管理器的撤消按钮。
struct MyView: View {
@Environment(\.undoManager) var undoManager: UndoManager?
var body: some View {
Button("Undo") { ... }
.disabled(!self.undoManager!.canUndo)
}
}
UndoManager.canUndo
不符合 KVO,因此使用一些通知发布者来跟踪状态,如下所示
struct MyView: View {
@Environment(\.undoManager) var undoManager
@State private var canUndo = false
// consider also other similar notifications
private let undoObserver = NotificationCenter.default.publisher(for: .NSUndoManagerDidCloseUndoGroup)
var body: some View {
Button("Undo") { }
.disabled(!canUndo)
.onReceive(undoObserver) { _ in
self.canUndo = self.undoManager!.canUndo
}
}
}
当涉及到 canRedo
时,我尝试了多种方法,我最终得到的是这个 - 所以观察 viewModel
(或 document
或任何其他支持撤消的数据源) 并更新 canUndo
/canRedo
以响应它的变化:
struct MyView: View {
@ObservedObject var viewModel: ViewModel
@Environment(\.undoManager) private var undoManger: UndoManager!
@State private var canUndo = false
@State private var canRedo = false
var body: some View {
RootView()
.onReceive(viewModel.objectWillChange) { _ in
canUndo = undoManger.canUndo
canRedo = undoManger.canRedo
}
if canUndo {
Button(
action: { undoManger?.undo() },
label: { Text("Undo") }
)
}
if canRedo {
Button(
action: { undoManger?.redo() },
label: { Text("Redo") }
)
}
...
我还将它包装在一个 standalone button 中(没有过度概括超出我自己需要的实现),它从我的角度消除了样板文件并使复杂性更加私密,所以它最终对我来说是这样的:
struct MyView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
RootView()
UndoManagerActionButton(
.undo,
willChangePublisher: viewModel.objectWillChange
)
UndoManagerActionButton(
.redo,
willChangePublisher: viewModel.objectWillChange
)
...