覆盖 UITextView 的 CMD + Z 键命令

Override UITextView's CMD + Z key command

是否可以覆盖 UITextViewcmd + zcmd + shift + z 的处理?

我试过了

class CustomTextView: UITextView {

    override var keyCommands: [UIKeyCommand]? {
       [
            // cmd + z (doesn't work)
            UIKeyCommand(input: "z", modifierFlags: [.command], action: #selector(undo)),
                
            // cmd + shift + z  (doesn't work)
            UIKeyCommand(input: "z", modifierFlags: [.command, .shift], action: #selector(redo)),
                
            // z (works)
            UIKeyCommand(input: "z", modifierFlags: [], action: #selector(z)),
        ]
    }
     
    // this doesn't help   
    override var undoManager: UndoManager? { return nil }
        






    // undo
    @objc private func undo() {
        print("undo")
    }

    // redo
    @objc private func redo() {
        print("redo")
    }

    // z
    @objc private func z() {
        print("z")
    }   
}

您可以使用 UITextView+UIResponder.swift 扩展来做到这一点:

import UIKit

extension UITextView {
    static var myUndoManager = UndoManager()

    fileprivate func handleUndo () { ... }
    fileprivate func handleRedo () { ... }

    override var undoManager : UndoManager? {
        return Self.myUndoManager
    }

    override func pressesBegan (
        _ presses: Set<UIPress>
      , with event: UIPressesEvent?
    )
    {
        for press in presses {
            guard
                let key = press.key
              , key.charactersIgnoringModifiers == "z"
            else { continue }

            switch key.modifierFlags {
                case .command:
                    handleUndo()
                case [ .command, .shift]:
                    handleRedo()
                default:
                    break
            }
        }
        super.pressesBegan (
            presses
          , with: event
        )
    }
}

相关 Apple 参考资料:

UIResponder::func pressesBegan(_:) https://developer.apple.com/documentation/uikit/uiresponder

Keyboards & Input::class UIKey https://developer.apple.com/documentation/uikit/uikey

另请参阅: https://whosebug.com/questions/tagged/uiresponder

为什么覆盖 keyCommands 不起作用?

UITextView 是不透明的,所以我自己看不到,但我认为它会覆盖 pressesBegan(_:with:) 并且不会为它处理的任何按键调用 super。如果没有对 super 的调用,UIPressesEvent 事件永远不会向上传播响应者链; keyCommands 永远不会看到他们。