Отмена и повторное перемещение объекта NSView, выполненное NSPanGestureRecognizer - PullRequest
0 голосов
/ 06 января 2020

Я работаю над примером настольного приложения для тестирования класса UndoManager, которым я не часто пользуюсь. В любом случае, идея заключается в следующем.

  1. Я создаю два NSView вспомогательных объекта вида (красный и синий). Они добавляются к объекту NSView, связанному с IBOutlet (panView).
  2. Я добавляю жест панорамирования (NSPanGestureRecognizer) к этим двум объектам вспомогательного представления.
  3. Приложения вызывают отмену менеджер, когда пользователь перемещает любой вспомогательный объект.

Ниже приведен весь мой код сверху вниз.

 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
          }
         }
     }
 }

enter image description here

Работает. Это не cra sh. Просто мне нужно дважды нажать Ctrl + Z, чтобы отменить ход. И я должен нажать Ctrl + Shift + Z дважды, чтобы повторить ход. Так что я не знаю, откуда эта пауза. Что я делаю не так, ты знаешь? Спасибо.

1 Ответ

0 голосов
/ 06 января 2020

Отмена регистрируется дважды: в sender.state == .began в redoMoveObject и в sender.state == .ended в undoMoveObject(dict). 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
    }
}
...