UITabbar的圆形按钮边缘可以响应点击

市场有相当一部分的app底部的tabBar是张这样的


00AF9A3C-81C5-43AE-ACB1-52C29D901884.png

中间蓝色的圆形区域可以响应点击事件,一般情况下,水平线上方的部分点击是没有反应的。今天就来讨论下这块区域响应的处理方式。
首先介绍下中间蓝色区域的实现方式。系统默认的tabBarItem是没有办法做到这点的,这里是在self.tabBar上添加一个view,用这个view来完整覆盖self.tabBar,所以这个view才是用来真正显示tabBarItem的地方。本文用的是LLTabBar,这里不做展开,感兴趣的伙伴去查下。
app启动后,我们打开xcode的hierarchy。可以看到如下的层次结构。


UITabbar的圆形按钮边缘可以响应点击_第1张图片
73015FB4-5C4A-4E03-8A4D-57A417B3AB89.png

我们知道iOS的触摸发生后,是沿着响应链找到最终响应触摸事件的view。在遇到分支时,首先会先判断最上方的分支是否能响应该事件(view本身或者是它的子view),如果能够响应的话,就不会走另外一条分支了。那么分支如何判断是否能够响应呢?答案就在以下这两个方法
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;

我们可以做个试验,针对UITabBar,因为UITabBar位于view层次的上方,触摸事件会先被它过滤。
我们新建一个UITabBar的类别,在类别里面写上方法

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
    return YES;
}

之后启动app,我们尝试点击其他不属于UITabBar的区域,发现所有的点击都失效了。因为触摸事件发生后,沿着响应链来到UILayoutContainerView时碰到了分支,由于UITabBar位于上方,所以会先调用UITabBar的pointInside: withEvent:和hitTest: withEvent:方法,而pointInside: withEvent:方法我们永远返回YES了,导致事件没法继续传递给它的兄弟view。
回到本篇的主题上,为了要解决该问题,单独只是重写这个方法还不够,因为我们还要指定具体是哪个view要响应。所以还必须重写hitTest: withEvent:方法。(实践证明,就算只是重写hitTest: withEvent:方法也是可以的。)
在刚刚UITabBar的类别里面添加如下的代码:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
    //如果点击区域就是在UITabBar范围内的话,就直接返回
    UIView *view = [super hitTest:point withEvent:event];
    if(view){
        return view;
    }
    if(view == nil){
        //找到中间的按钮
        UIView *publishBtn;
        [self getPublishBtn:self accordView:&publishBtn];
        if(publishBtn != nil){
            //判断事件的触发点是否在中间按钮的区域内,不是返回nil
            CGPoint newPoint = [publishBtn convertPoint:point fromView:self];
            if(CGRectContainsPoint(publishBtn.bounds, newPoint)){
                return publishBtn;
            }
        }
    }
    return nil;
}

-(void)getPublishBtn:(UIView*)superView accordView:(UIView**)accordView{
    for(UIView *view in [superView subviews]){
        if([view isKindOfClass:[LLTabBarItem class]]){
            LLTabBarItem *item = (LLTabBarItem*)view;
            if(item.tabBarItemType == LLTabBarItemRise){
                for(UIView *subView in [item subviews]){
                    if([subView isKindOfClass:[UIImageView class]]){
                        *accordView = subView;
                    }
                }
            }
        }
        if([view subviews].count > 0){
            [self getPublishBtn:view accordView:accordView];
        }
    }
}

这样,即使触发点落在UITabBar的区域之外,一样可以触发中间按钮的点击事件。
这里需要注意的是pointInside: withEvent:和hitTest: withEvent:方法不要写在子view里面,因为一旦UITabBar的这两个方法判断不再它的响应范围内,就不会再去询问子view。


如果本文让你有那么点觉得“I get”的感觉,请点个赞呗!写作很辛苦,路过请点赞!

你可能感兴趣的:(UITabbar的圆形按钮边缘可以响应点击)