在
iOS 11
中,按钮和文本字段作为 UIToolBar
的子视图没有响应。将视图层次结构与 iOS 10
进行比较,我们发现 _UIToolBarContentView
的所有子视图上都有一个 UIToolBar
。
例如,
UIToolBar
的新布局打破了slacktextviewcontroller
https://github.com/slackhq/SlackTextViewController/issues/604
需要一个适用于
iOS 10/11
的解决方案。
要解决
iOS11
的问题(兼容较低版本)你只需要
在 layoutSubview
作为子视图添加到 UI 层次结构之后立即创建 UIToolBar
。
在这种情况下
_UIToolbarContentView
降低到UIToolBar的第一个子视图,你可以
像以前一样将所有子视图添加到更高的位置。
例如在
ObjC
,
UIToolbar *toolbar = [UIToolbar new];
[self addSubview: toolbar];
[toolbar layoutIfNeeded];
<here one can add all subviews needed>
同样的问题发生在slacktextviewcontroller
我已经在我的案例中解决了这个问题。我重写了UIToobar子类中的
layoutSubviews
方法,并将userInteractionEnable
的_UIToolbarContentView
更改为NO。
- (void)layoutSubviews {
[super layoutSubviews];
NSArray *subViewArray = [self subviews];
for (id view in subViewArray) {
if ([view isKindOfClass:(NSClassFromString(@"_UIToolbarContentView"))]) {
UIView *testView = view;
testView.userInteractionEnabled = NO;
}
}
}
您可以使用
hitTest(_:with:)
方法。
首先,在
contentView
中创建属性UIToolbar
:
open private(set) var contentView: UIView = UIView()
然后,使
contentView
的框架与UIToolbar
的框架相同。例如:
contentView.frame = bounds
contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addSubview(contentView)
最后,重写
hitTest(_:with:)
方法:
open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if self.point(inside: point, with: event) {
if let hitTestView = contentView.hitTest(point, with: event) {
return hitTestView
} else {
return self
}
} else {
return nil
}
}
在这种情况下,如果您想通过简单地添加其他视图来自定义工具栏,您应该 将它们添加到
contentView
,以便它们能够正确定位。
新的
UIToolbar
对象主动使用基于约束的布局,因此最好重写- (void)updateConstraints
方法。要在 UIToolbar
对象上呈现自定义视图,最好对其进行子类化并添加自定义容器视图:
- (UIView *)containerView
{
if (_containerView) {
return _containerView;
}
_containerView = [[UIView alloc] initWithFrame:self.bounds];
_containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
return _containerView;
}
现在您可以安全地将自定义视图添加到容器视图中。为了使自定义视图具有响应能力,我们需要在约束更新后更改工具栏子视图的顺序:
- (void)updateConstraints
{
[super updateConstraints];
[self bringSubviewToFront:self.containerView];
}
请注意,如果您将
UINavigationController
与自定义工具栏一起使用,则应在添加自定义子视图之前强制它更新其布局。
在仅具有自动布局和代码的 Swift 中,对我有用的是按照 malex 在添加项目之前、设置约束之后进行布局。
添加约束
toolbar.layoutIfNeeded()
toolbar.setItems([...(您的项目)],动画:true)
有一种奇怪的方法可以做到这一点。
[self.textInputbar sendSubviewToBack:[self.textInputbar.subviews lastObject]];