锚定到 InputAccessoryView 的按钮仅在其框架中工作

Button anchored to InputAccessoryView working only in its frame

设置

我通过以下方式在 UIViewController 中实现了 inputAcessoryView

override var inputAccessoryView: UIView? {

    get {

        return bottomBarView
    }
}
override var canBecomeFirstResponder: Bool {

    return true
}

fileprivate lazy var bottomBarView: UIView = {

    let view = UIView()
    let separatorLineView = UIView()

    view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height / 9)
    view.backgroundColor = .white

    /...

    separatorLineView.backgroundColor = UIColor(r: 220, g: 220, b: 220, a: 1)
    separatorLineView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(separatorLineView)
    separatorLineView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
    separatorLineView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
    separatorLineView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
    separatorLineView.heightAnchor.constraint(equalToConstant: 1).isActive = true

    view.addSubview(self.photoButton)
    self.photoButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    self.photoButton.centerYAnchor.constraint(equalTo: separatorLineView.centerYAnchor, constant: -12).isActive = true
    self.photoButton.widthAnchor.constraint(equalToConstant: view.frame.width / 4.5).isActive = true
    self.photoButton.heightAnchor.constraint(equalToConstant: view.frame.width / 4.5).isActive = true

    return view
}()

photoButton.touchUpInside.

上执行一个操作

问题

该按钮只能在 inputAccessoryView 框架中包含的部分中单击:如果我在外部单击它,则什么也不会发生。

有什么快速的方法可以让它像这样工作吗?

我曾尝试将 photoButton 移出 bottomBarView 并将其添加到视图中,但是:

提前致谢。

这几天我自己在工作中遇到了这个问题。

您需要为 inputAcessoryView 实现自己的 hitTest UIResponder 方法。可能看起来像这样的东西:

override func hitTest(_ point: CGPoint, 
        with event: UIEvent?) -> UIView? {

    if self.photoButton.frame.contains(point) {
        return self.photoButton
    }

    return super.hitTest(point, with: event)
}

更多信息可见in this related question

您遇到的问题是 inputAccessoryView(对您来说是 bottomBarView)没有高度。因此,您添加的所有子视图都在其范围之外。如果您要设置 clipsToBounds = true,您会发现一切都消失了。

如您所见,问题在于这些子视图没有获得触摸事件,因为它们在其父视图的范围之外。来自 Apple 的文档:

If a touch location is outside of a view’s bounds, the hitTest:withEvent: method ignores that view and all of its subviews. As a result, when a view’s clipsToBounds property is NO, subviews outside of that view’s bounds are not returned even if they happen to contain the touch.

Understanding Event Handling, Responders, and the Responder Chain

解决方法是让 inputAccessoryView 成为正确的高度。 self.view.frame.height / 9 在您的示例中是 0,因为在您使用它时尚未设置框架。

相反,创建一个 UIView 子类,包含以下重要部分:

class BottomBarView: UIView {

    init(frame: CGRect) {
        super.init(frame: frame)

        autoresizingMask = .flexibleHeight

        let someView = UIView()
        addSubview(someView)
        someView.translatesAutoresizingMaskIntoConstraints = false
        someView.topAnchor.constraint(equalTo: topAnchor).isActive = true
        someView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
        someView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
        someView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true

        // In this case, the top, bottom, and height constraints will 
        // determine the height of the inputAccessoryView
        someView.heightAnchor.constraint(equalToConstant: 100).isActive = true
    }

    override var intrinsicContentSize: CGSize {
        return CGSize(width: UIViewNoIntrinsicMetric, height: 0)
    }
}

尝试添加一个按钮。你会看到现在它得到了一个触摸事件,因为它现在在它的超级视图的范围内。