锚定到 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
并将其添加到视图中,但是:
- 我需要
photoButton
成为 "anchored" 到 inputAccessoryView
,但似乎 inputAccessoryView
在视图中没有锚点属性? (我只能通过 bang 展开来访问它们的 frame
属性)
- 当我这样做时,
photoButton
部分隐藏在 inputAccessoryView
后面,我无法用 view.bringSubview(ToFront:)
将其前移
提前致谢。
这几天我自己在工作中遇到了这个问题。
您需要为 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)
}
}
尝试添加一个按钮。你会看到现在它得到了一个触摸事件,因为它现在在它的超级视图的范围内。
设置
我通过以下方式在 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
并将其添加到视图中,但是:
- 我需要
photoButton
成为 "anchored" 到inputAccessoryView
,但似乎inputAccessoryView
在视图中没有锚点属性? (我只能通过 bang 展开来访问它们的frame
属性) - 当我这样做时,
photoButton
部分隐藏在inputAccessoryView
后面,我无法用view.bringSubview(ToFront:)
将其前移
提前致谢。
这几天我自己在工作中遇到了这个问题。
您需要为 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)
}
}
尝试添加一个按钮。你会看到现在它得到了一个触摸事件,因为它现在在它的超级视图的范围内。