【问题标题】:iOS keyboard dismissal with multiple UIGestureRecognizers使用多个 UIGestureRecognizers 解除 iOS 键盘
【发布时间】:2017-06-15 20:28:04
【问题描述】:

在包含UITextFieldUITableView 的主应用程序视图中,如果在键盘外检测到轻按时,我会使用UITapGestureRecognizer 的“常规”代码来关闭虚拟键盘。 m 编辑UITextField的内容。

一个附加功能是,只有在实际显示虚拟键盘时才启用此功能 - 如果虚拟键盘不可见,我不希望“背景点击”导致编辑结束,但我也不希望背景点击触发它们的正常行为 - 如果虚拟键盘当前正在显示,它们应该被消耗掉。

override func viewDidLoad() {
    ...

    tapper = UITapGestureRecognizer(target: self, action: #selector(viewTapped))

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardShown), name:
        NSNotification.Name(rawValue: "UIKeyboardDidShowNotification"), object: nil)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardHidden), name:
        NSNotification.Name(rawValue: "UIKeyboardDidHideNotification"), object: nil)
}

@IBAction func keyboardShown(_ sender: AnyObject) {
    view.addGestureRecognizer(tapper!)
}

@IBAction func keyboardHidden(_ sender: AnyObject) {
    view.removeGestureRecognizer(tapper!)
}

@IBAction func viewTapped(_ sender: AnyObject) {
    view.endEditing(false)
}

这个大部分可以工作,除了UITableView有交互式标题单元,每个有一个UITapGestureRecognizer附加。

最终结果是,如果我单击标题单元格,则该单元格上的手势识别器会被触发,而不是父视图上的手势识别器,并且键盘不会被关闭。如果我点击数据单元格,一切正常。

如果重要的话,我的 UITableView 有自己的 UIViewController 子类,并且包含在嵌套的 UIView 中 - 该表太复杂,无法在我的主视图控制器中包含该代码。

当附加父视图的识别器时,如何防止子视图的手势识别器处理这些点击,以便父视图可以处理它们?

【问题讨论】:

  • 建议您的视图控制器使用自定义视图类作为其根目录是否过于生硬,它会覆盖hitTest:withEvent: 来执行“用户是否触摸了屏幕?”测试,而不是使用手势识别器?这将允许被动聆听——你不需要消耗触摸,你可以像往常一样传递它,但也知道有一个触摸进入系统。
  • @Tommy 我遗漏了一个重要的细节(现在包括在内) - 我需要(有条件地)使用这些触摸,因为我不希望在文本以外的任何内容时触发正常的触摸事件字段被触摸 - 我只想让键盘消失。
  • @Tommy 感谢您的提示,我现在有了更好的工作解决方案! :)

标签: ios swift user-interface


【解决方案1】:

我通过观察UITableView's 控制器中的虚拟键盘通知,跟踪键盘可见性状态,然后在标题单元格的手势识别器上实现此UIGestureRecognizerDelegate 方法,实现了我认为的“临时”解决方案:

func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    return !keyboardShowing
}

这从子视图中的主视图复制了一定数量的功能,实际上不需要知道键盘的状态。我仍在寻找一种可以完全从父视图中处理的方法。


编辑 - 感谢@Tommy 的提示,我现在有了一个更好的解决方案,无需在子视图中跟踪键盘状态。

我的父视图不再使用UIGestureRecognizer,而是使用UIView 的自定义子类来跟踪触摸事件,并有条件地忽略它们:

class KeyboardDismissingView: UIView {

    private var keyboardVisible = false

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        guard let r = super.hitTest(point, with: event) else { return nil }
        var v : UIView! = r
        while v != nil {
            if v is UITextField {
                return r
            }
            v = v.superview
        }

        if keyboardVisible {
            self.endEditing(false)
            return nil
        }

        return r
    }

    func setup() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardShown), name:
            NSNotification.Name(rawValue: "UIKeyboardDidShowNotification"), object: nil)

        NotificationCenter.default.addObserver(self, selector: #selector(keyboardHidden), name:
            NSNotification.Name(rawValue: "UIKeyboardDidHideNotification"), object: nil)
    }

    @IBAction func keyboardShown(_ sender: AnyObject) {
        keyboardVisible = true
    }

    @IBAction func keyboardHidden(_ sender: AnyObject) {
        keyboardVisible = false
    }

    override init (frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
        setup()
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-28
    • 2011-10-18
    • 2016-02-05
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 2013-10-22
    相关资源
    最近更新 更多