Łuk*_*asz 1 macos nsundomanager swift swiftui
我正在尝试了解 UndoManager 的工作原理。我制作了一个小应用程序来撤消/重做某些操作。我有几个问题,我在文档中找不到答案:
我知道 UndoManager 可以通过以下方式在 View 中访问
@Environment(\.undoManager) var undoManager
杰出的。但在这种情况下,它仅在视图中可用,如果我想在结构中更深的地方使用它,我必须通过模型将其传递给对象...是否有一种方法可以在其他对象中访问相同的 UndoManager ?模型、数据...我可以更方便,特别是如果有很多撤消分组。如果我在文档(或其他地方)中创建 UndoManager,则主菜单“编辑”->“撤消”、“重做”将看不到它
在GitHub 上的应用程序存储库中,我实现了撤消/重做。对我来说(哈哈)它看起来不错,甚至可以工作,但不适用于第一次行动。第一个操作撤消会导致Thread 1: signal SIGABRT错误。经过三个操作后,我可以撤消最后两个操作……砰。有问题
import Foundation
import SwiftUI
struct CustomView: View {
@ObservedObject var model: PointsViewModel
@Environment(\.undoManager) var undoManager
@GestureState var isDragging: Bool = false
@State var dragOffsetDelta = CGPoint.zero
var formatter: NumberFormatter {
let formatter = NumberFormatter()
formatter.allowsFloats = true
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 5
return formatter
}
var body: some View {
HStack {
VStack(alignment: .leading, spacing: 10) {
ForEach(model.insideDoc.points.indices, id:\.self) { index in
HStack {
TextField("X", value: $model.insideDoc.points[index].x, formatter: formatter)
.frame(width: 80, alignment: .topLeading)
TextField("Y", value: $model.insideDoc.points[index].y, formatter: formatter)
.frame(width: 80, alignment: .topLeading)
Spacer()
}
}
Spacer()
}
ZStack {
ForEach(model.insideDoc.points.indices, id:\.self) { index in
Circle()
.foregroundColor(index == model.selectionIndex ? .red : .blue)
.frame(width: 20, height: 20, alignment: .center)
.position(model.insideDoc.points[index])
//MARK: - drag point
.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .local)
.onChanged { drag in
if !isDragging {
dragOffsetDelta = drag.location - model.insideDoc.points[index]
model.selectionIndex = index
let now = model.insideDoc.points[index]
undoManager?.registerUndo(withTarget: model, handler: { model in
model.insideDoc.points[index] = now
model.objectWillChange.send()
})
undoManager?.setActionName("undo Drag")
}
model.insideDoc.points[index] = drag.location - dragOffsetDelta
}
.updating($isDragging, body: { drag, state, trans in
state = true
model.objectWillChange.send()
})
.onEnded({drag in model.selectionIndex = index
model.insideDoc.points[index] = drag.location - dragOffsetDelta
model.objectWillChange.send()
})
)
}
}.background(Color.orange.opacity(0.5))
//MARK: - new point
.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .local)
.onEnded{ loc in
let previousIndex = model.selectionIndex
undoManager?.registerUndo(withTarget: model, handler: {model in
model.insideDoc.points.removeLast()
model.selectionIndex = previousIndex
model.objectWillChange.send()
})
model.insideDoc.points.append(loc.location)
model.selectionIndex = model.insideDoc.points.count - 1
model.objectWillChange.send()
}
)
//MARK: - delete point
.onReceive(deleteSelectedObject, perform: { _ in
if let deleteIndex = model.selectionIndex {
let deleted = model.insideDoc.points[deleteIndex]
undoManager?.registerUndo(withTarget: model, handler: {model in
model.insideDoc.points.insert(deleted, at: deleteIndex)
model.objectWillChange.send()
})
undoManager?.setActionName("remove Point")
model.insideDoc.points.remove(at: deleteIndex)
model.objectWillChange.send()
model.selectionIndex = nil
}
})
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
只是在寻找其他东西时偶然发现了这一点,我想我应该分享我自己的经验。在我的应用程序中,我对 UndoManager 有时存在感到抓狂,并且我的调试显示,在给定视图的生命周期内,撤消管理器可能会发生变化。我将 UndoManager 存储在全局状态对象中,以便应用程序所做的一切都可以(可能)注册为撤消。所以现在我得到这样的代码:
struct MyView: View {
@Environment(\.undoManager) var undoManager
@ObservedObject var applicationStateModel ...
...
var body: some View {
VStack {
...
}
.onChange(of: undoManager) { newManager in
applicationStateModel.undoManager = newManager
}
.onAppear {
applicationStateModel.undoManager = undoManager
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2075 次 |
| 最近记录: |