iOS11 UIToolBar Contentview

To solve the problem for iOS11 (compatible with lower versions) you only need to make layoutSubview right after UIToolBar was added as a subview to UI hierarchy.

In this case _UIToolbarContentView lowers to the first subview of UIToolBar, and you can add all your subviews higher as before.

For example in ObjC,

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

    <here one can add all subviews needed>

The same problem happens with slacktextviewcontroller


You can just use the hitTest(_:with:) method.

  1. First, create a property contentView in UIToolbar:

    open private(set) var contentView: UIView = UIView()
    
  2. Then, make the contentView's frame the same as the UIToolbar's. For example:

    contentView.frame = bounds
    contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    addSubview(contentView)
    
  3. Finally, override the hitTest(_:with:) method:

    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
        }
    }
    

In this situation, if you want to customize a toolbar by simply adding additional views, you should add them to the contentView so they will be positioned appropriately.


I have solved this problem in my case. I rewrite the layoutSubviews method in subclass of UIToobar and change the userInteractionEnable of _UIToolbarContentView into 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;
         }
     }

}