为啥#selector 不为 iPad 的键盘快捷键调用处理程序方法?

Posted

技术标签:

【中文标题】为啥#selector 不为 iPad 的键盘快捷键调用处理程序方法?【英文标题】:Why #selector doesn't call handler method for iPad's keyboard shortcuts?为什么#selector 不为 iPad 的键盘快捷键调用处理程序方法? 【发布时间】:2018-10-29 15:09:18 【问题描述】:

我有一个用于构造 UIBarButtonItems 的类:

enum KeyboardToolbarButton: Int 

    case done = 0
    case cancel
    case back, backDisabled
    case forward, forwardDisabled

    func createButton(target: Any?, action: Selector?) -> UIBarButtonItem 
        var button: UIBarButtonItem!

        switch self 
        case .back:
            button = UIBarButtonItem(title: "<=", style: .plain, target: target, action: action)
        case .backDisabled:
            button = UIBarButtonItem(title: "<=", style: .plain, target: target, action: action)
            button.isEnabled = false
        case .forward:
            button = UIBarButtonItem(title: "=>", style: .plain, target: target, action: action)
        case .forwardDisabled:
            button = UIBarButtonItem(title: "=>", style: .plain, target: target, action: action)
            button.isEnabled = false
        case .done:
            button = UIBarButtonItem(title: "DONE", style: .plain, target: target, action: action)
        case .cancel:
            button = UIBarButtonItem(title: "CANCEL", style: .plain, target: target, action: action)
        
        button.tag = rawValue
        return button
    

    static func detectType(barButton: UIBarButtonItem) -> KeyboardToolbarButton? 
        return KeyboardToolbarButton(rawValue: barButton.tag)
    

从 KeyboardToolbarButton 构造 KeyboardToolbar 的类:

class KeyboardToolbar 

    weak var toolBarDelegate: KeyboardToolbarDelegate?
    var textField: UITextField!

    init(textField: UITextField) 

        self.textField = textField
        self.textField.autocorrectionType = .no
        self.textField.inputAssistantItem.leadingBarButtonGroups = []
        self.textField.inputAssistantItem.trailingBarButtonGroups = []
    

    func setup(leftButtons: [KeyboardToolbarButton], rightButtons: [KeyboardToolbarButton]) 

        let leftBarButtons = leftButtons.map  (item) -> UIBarButtonItem in
            return item.createButton(target: self, action: #selector(self.buttonTapped(sender:)))
        

        let rightBarButtons = rightButtons.map  (item) -> UIBarButtonItem in
            return item.createButton(target: self, action: #selector(self.buttonTapped(sender:)))
        

        let groupLeading: UIBarButtonItemGroup = UIBarButtonItemGroup.init(barButtonItems: leftBarButtons, representativeItem: nil)
        let groupTrailing: UIBarButtonItemGroup = UIBarButtonItemGroup.init(barButtonItems: rightBarButtons, representativeItem: nil)

        textField.inputAssistantItem.leadingBarButtonGroups.append(groupLeading)
        textField.inputAssistantItem.trailingBarButtonGroups.append(groupTrailing)
    


    @objc func buttonTapped(sender: UIBarButtonItem) 
        if let type = KeyboardToolbarButton.detectType(barButton: sender) 
            print(type)
            toolBarDelegate?.keyboardToolbar(button: sender, type: type, tappedIn: self)
        
    


和委托:

protocol KeyboardToolbarDelegate: class 
    func keyboardToolbar(button: UIBarButtonItem, type: KeyboardToolbarButton, tappedIn toolbar: KeyboardToolbar)

这是我使用键盘工具栏的方法:

class ViewController: UIViewController 

    @IBOutlet weak var textField: UITextField!

    override func viewDidLoad() 
        super.viewDidLoad()


        addButtons(for: textField, setLeftButtons: [.back, .forward], andRightButtons: [.done])
    


    private func addButtons(for textField: UITextField, setLeftButtons leftButtons: [KeyboardToolbarButton] = [], andRightButtons rightButtons: [KeyboardToolbarButton] = []) 
        let toolbar = KeyboardToolbar(textField: textField)
        toolbar.toolBarDelegate = self
        toolbar.setup(leftButtons: leftButtons, rightButtons: rightButtons)
    



extension ViewController: KeyboardToolbarDelegate 
    func keyboardToolbar(button: UIBarButtonItem, type: KeyboardToolbarButton, tappedIn toolbar: KeyboardToolbar) 

        print("Tapped button type: \(type)")


    

这是它的工作原理(此功能仅在 iPad 上可用)

所以,问题在于 @objc func buttonTapped(sender: UIBarButtonItem) 从不调用。那么,#selector(self.buttonTapped(sender:) 没有连接到处理程序。如何解决?

更新:

根据 Taras Chernyshenko 的回答,我将 KeyboardToolbar 添加为 ViewController 的成员:

class ViewController: UIViewController 

    @IBOutlet weak var textField: UITextField!
    var toolbar: KeyboardToolbar!

    override func viewDidLoad() 
        super.viewDidLoad()

        addButtons(for: textField, setLeftButtons: [.back, .forward], andRightButtons: [.done])
    


    private func addButtons(for textField: UITextField, setLeftButtons leftButtons: [KeyboardToolbarButton] = [], andRightButtons rightButtons: [KeyboardToolbarButton] = []) 
        toolbar = KeyboardToolbar(textField: textField)
        toolbar.toolBarDelegate = self
        toolbar.setup(leftButtons: leftButtons, rightButtons: rightButtons)
    


【问题讨论】:

【参考方案1】:

问题在于您的设计。在func setup(leftButtons:, rightButtons:) 函数中的KeyboardToolbar 类中你接下来要做的:

let leftBarButtons = leftButtons.map  (item) -> UIBarButtonItem in
    return item.createButton(target: self, action: #selector(self.buttonTapped(sender:)))

在这里,您将 action target 设置为 KeyboardToolbar 类。

接下来在addButtons(for textField:, setLeftButtons leftButtons:, andRightButtons rightButtons:)ViewController 中设置按钮

let toolbar = KeyboardToolbar(textField: textField)
toolbar.toolBarDelegate = self
toolbar.setup(leftButtons: leftButtons, rightButtons: rightButtons)

但在此函数toolbar 被释放后,操作无法达到其目标。

为了简单的修复,将toolbar 存储到类属性中

class ViewController: UIViewController 

    @IBOutlet weak var textField: UITextField!

    var toolbar = KeyboardToolbar?
    override func viewDidLoad() 
        super.viewDidLoad()


        addButtons(for: textField, setLeftButtons: [.back, .forward], andRightButtons: [.done])
    


    private func addButtons(for textField: UITextField, setLeftButtons leftButtons: [KeyboardToolbarButton] = [], andRightButtons rightButtons: [KeyboardToolbarButton] = []) 
        let toolbar = KeyboardToolbar(textField: textField)
        toolbar.toolBarDelegate = self
        toolbar.setup(leftButtons: leftButtons, rightButtons: rightButtons)
        self.toolbar = toolbar
    


【讨论】:

谢谢。现在工作。但是您发送的代码中有一些小错误。它需要将 KeyboardToolbar 声明为 var toolbar: KeyboardToolbar!。然后在 private func addButtons(for textField: UITextField, setLeftButtons leftButtons: 我们需要使用相同的变量。

以上是关于为啥#selector 不为 iPad 的键盘快捷键调用处理程序方法?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 iPad 键盘高度在横向模式下是 1024 像素?

resignFirstResponder 无法关闭我在 iPad 上的自定义键盘。为啥?

WPF 利用键盘钩子来捕获键盘,做一些不为人知的事情...完整实例

iOS中的键盘快捷键?

ubuntu 为啥每次启动把小键盘关闭

为啥苹果iPad彻底卖不出去了!终于知道真相