iOS11 UIToolBar 内容视图

iOS11 UIToolBar Contentview

iOS 11 中,按钮和文本字段作为 UIToolBar 的子视图没有响应。将视图层次结构与 iOS 10 进行比较,我们看到 UIToolBar 的所有子视图都有一个 _UIToolBarContentView

例如,UIToolBar 的新布局打破了 slacktextviewcontroller https://github.com/slackhq/SlackTextViewController/issues/604

需要一个适用于 iOS 10/11 的解决方案。

有一种奇怪的方法。

[self.textInputbar sendSubviewToBack:[self.textInputbar.subviews lastObject]];

解决iOS11的问题(兼容低版本)只需要 在 UIToolBar 作为子视图添加到 UI 层次结构之后立即制作 layoutSubview

在这种情况下 _UIToolbarContentView 降低到 UIToolBar 的第一个子视图,您可以 像以前一样将所有子视图添加得更高。

例如 ObjC,

    UIToolbar *toolbar = [UIToolbar new];
    [self addSubview: toolbar];
    [toolbar layoutIfNeeded];

    <here one can add all subviews needed>

同样的问题发生在slacktextviewcontroller

你可以只使用hitTest(_:with:)方法。

  1. 首先,在UIToolbar中创建一个属性contentView

    open private(set) var contentView: UIView = UIView()
    
  2. 然后,使contentView的帧与UIToolbar的帧相同。例如:

    contentView.frame = bounds
    contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    addSubview(contentView)
    
  3. 最后,覆盖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 中,以便将它们放置在适当的位置。

我已经解决了这个问题。我在 UIToobar 的子类中重写了 layoutSubviews 方法,并将 _UIToolbarContentViewuserInteractionEnable 更改为 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;
         }
     }

}

新的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 中,对我有用的是按照 在添加项目之前但在设置约束之后提到的布局。

  • 实例化您的工具栏
  • 将其添加到您的视图中
  • 添加约束

    toolbar.layoutIfNeeded()

    toolbar.setItems([...(您的项目)],动画:真)