Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 撤消和重新执行NSPanGestureRecognizer执行的NSView对象移动_Swift_Macos_Gesture_Nsview_Nsundomanager - Fatal编程技术网

Swift 撤消和重新执行NSPanGestureRecognizer执行的NSView对象移动

Swift 撤消和重新执行NSPanGestureRecognizer执行的NSView对象移动,swift,macos,gesture,nsview,nsundomanager,Swift,Macos,Gesture,Nsview,Nsundomanager,我正在开发一个示例桌面应用程序来测试UndoManager类,我不经常使用它。无论如何,以下是想法 我创建了两个子视图对象(红色和蓝色)。它们被添加到连接到NSView对象(panView)的IBOutlet中 我将平移手势(nspangesturererecognizer)添加到这两个子视图对象中 当用户移动任一子视图对象时,应用程序调用撤消管理器 下面是我自上而下的全部代码 import Cocoa class ViewController: NSViewController {

我正在开发一个示例桌面应用程序来测试
UndoManager
类,我不经常使用它。无论如何,以下是想法

  • 我创建了两个子视图对象(红色和蓝色)。它们被添加到连接到
    NSView
    对象(panView)的IBOutlet中
  • 我将平移手势(
    nspangesturererecognizer
    )添加到这两个子视图对象中
  • 当用户移动任一子视图对象时,应用程序调用撤消管理器
  • 下面是我自上而下的全部代码

     import Cocoa
    
     class ViewController: NSViewController {
         // MARK: - Variables
         var myView1 = NSView()
         var myView2 = NSView()
         var uuid1 = String()
         var uuid2 = String()
    
    
         // MARK: - IBOutlet
         @IBOutlet weak var panView: NSView!
    
    
         // MARK: - Life cycle
         override func viewDidLoad() {
             super.viewDidLoad()
    
             /* myView */
             uuid1 = UUID().uuidString
             myView1 = NSView(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: 100, height: 100)))
             myView1.identifier = NSUserInterfaceItemIdentifier(rawValue: uuid1)
             myView1.wantsLayer = true
             if let myLayer1 = myView1.layer {
              myLayer1.backgroundColor = NSColor.red.cgColor
             }
             panView.addSubview(myView1)
    
             uuid2 = UUID().uuidString
             myView2 = NSView(frame: CGRect(origin: CGPoint(x: 400, y: 200), size: CGSize(width: 100, height: 100)))
             myView2.identifier = NSUserInterfaceItemIdentifier(rawValue: uuid2)
             myView2.wantsLayer = true
             if let myLayer2 = myView2.layer {
              myLayer2.backgroundColor = NSColor.blue.cgColor
             }
             panView.addSubview(myView2)
    
             /* pangesture */
             let panRecognizer1 = NSPanGestureRecognizer.init(target: self, action: #selector(panPictureView(_:)))
             let panRecognizer2 = NSPanGestureRecognizer.init(target: self, action: #selector(panPictureView(_:)))
             myView1.addGestureRecognizer(panRecognizer1)
             myView2.addGestureRecognizer(panRecognizer2)
         }         
    
         // MARK: - Pan gesture
         @objc func panPictureView(_ sender: NSPanGestureRecognizer) {
             let translation = sender.translation(in: self.view)
             if let movingObject = sender.view {
              let newPosition = CGPoint(x: movingObject.frame.origin.x + translation.x, y: movingObject.frame.origin.y + translation.y)
              movingObject.setFrameOrigin(newPosition)
              sender.setTranslation(CGPoint.zero, in: self.view)
              if sender.state == .began {
                  if let rawID = sender.view?.identifier?.rawValue {
                      let dict = ["point": movingObject.frame.origin, "rawID": rawID] as [String : Any]
                      redoMoveObject(dict)
                  }
              }
              else if sender.state == .ended {
                  if let rawID = sender.view?.identifier?.rawValue {
                      let dict = ["point": movingObject.frame.origin, "rawID": rawID] as [String : Any]
                      undoMoveObject(dict)
                  }
              }
             }
         }
    
    
         // MARK: - Undoing move
         @objc func undoMoveObject(_ newObject: [String : Any]) {
             undoManager?.registerUndo(withTarget: self, selector: #selector(redoMoveObject(_:)), object: newObject)
             undoManager?.setActionName("Move Object")
             if let point = newObject["point"] as? CGPoint, let rawID = newObject["rawID"] as? String {
              if rawID == uuid1 {
                  myView1.frame.origin = point
              }
              else {
                  myView2.frame.origin = point
              }
             }
         }
    
         @objc func redoMoveObject(_ newObject: [String : Any]) {
             undoManager?.registerUndo(withTarget: self, selector: #selector(undoMoveObject(_:)), object: newObject)
             undoManager?.setActionName("Move Object")
             if let point = newObject["point"] as? CGPoint, let rawID = newObject["rawID"] as? String {
              if rawID == uuid1 {
                  myView1.frame.origin = point
              }
              else {
                  myView2.frame.origin = point
              }
             }
         }
     }
    


    它起作用了。它不会崩溃。只是我必须按Command+Z两次才能撤消移动。我必须按Command+Shift+Z两次才能重新移动。所以我不知道这个停顿是从哪里来的。我做错了什么,你知道吗?谢谢。

    撤消注册两次:在
    redoMoveObject
    中的
    sender.state==.start
    和在
    undoMoveObject(dict)中的
    sender.state=.end
    undoMoveObject
    redoMoveObject
    执行相同的操作并相互注册,它们可以合并为一个注册自身的函数

    例如:

    // MARK: - Pan gesture
    @objc func panPictureView(_ sender: NSPanGestureRecognizer) {
        if let movingObject = sender.view {
            if sender.state == .began { // register undo before first move
                if let rawID = movingObject.identifier?.rawValue {
                    let dict = ["point": movingObject.frame.origin, "rawID": rawID] as [String : Any]
                    undoMoveObject(dict)
                }
            }
            let translation = sender.translation(in: self.view)
            sender.setTranslation(CGPoint.zero, in: self.view)
            let newPosition = CGPoint(x: movingObject.frame.origin.x + translation.x, y: movingObject.frame.origin.y + translation.y)
            movingObject.setFrameOrigin(newPosition)
        }
    }
    
    // MARK: - Undoing move
    @objc func undoMoveObject(_ newObject: [String : Any]) {
        if let point = newObject["point"] as? CGPoint, let rawID = newObject["rawID"] as? String {
            var movingObject: NSView
            if rawID == uuid1 {
                movingObject = myView1
            }
            else {
                movingObject = myView2
            }
            // register current frame origin for redo/undo
            let dict = ["point": movingObject.frame.origin, "rawID": rawID] as [String : Any]
            undoManager?.registerUndo(withTarget: self, selector: #selector(undoMoveObject(_:)), object: dict)
            undoManager?.setActionName("Move Object")
            // undo/redo
            movingObject.frame.origin = point
        }
    }
    

    谢谢休息几个小时后我会去看一看。真令人印象深刻。谢谢。