增加点击区域

作者: 宁静1致远 | 来源:发表于2018-08-07 16:32 被阅读4次

项目中很多时候需要扩大点击(交互)区域,或子试图超出了父视图后,无法点击或交互等,我们可以通过响应者链
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

来处理,下面是我封装的一个小控件,分享给大家 show.jpg
1、在category里添加属性
-(void)setEnlargedMargin:(CGFloat)enlargedMargin{
    [self setEnlargeEdge:UIEdgeInsetsMake(enlargedMargin, enlargedMargin, enlargedMargin, enlargedMargin)];
}

-(void)setEnlargeEdge:(UIEdgeInsets)enlargeEdge{
    //拓展后的rect
    CGRect rect=CGRectMake(self.bounds.origin.x-enlargeEdge.left, self.bounds.origin.y-enlargeEdge.top, self.frame.size.width+enlargeEdge.left+enlargeEdge.right, self.frame.size.height+enlargeEdge.top+enlargeEdge.bottom);
    //存入
    objc_setAssociatedObject(self, &key_yjn_enlarged, @[NSStringFromCGRect(rect)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    //挣脱父试图束缚
    CGRect windowConvertRect = [self convertRect:self.bounds toView:[[[UIApplication sharedApplication] delegate] window]];
    [self freeView:self.superview rect:windowConvertRect enlargeEdge:enlargeEdge];
}

-(NSArray *)enlargedRect{
    NSArray *enlargedArr = objc_getAssociatedObject(self, &key_yjn_enlarged);
    if (enlargedArr) {
        return enlargedArr;
    }else{
        return @[NSStringFromCGRect(self.bounds)];
    }
}

2、挣脱父试图束缚

#pragma mark - 挣脱父试图束缚
-(void)freeView:(UIView *)superview rect:(CGRect)rect enlargeEdge:(UIEdgeInsets)enlargeEdge{
    if(superview == nil) return;
    
    //坐标转换
    UIWindow * window=[[[UIApplication sharedApplication] delegate] window];
    CGRect selfRect = [self convertRect:self.bounds toView:window];
    CGRect superViewRect = [superview convertRect:superview.bounds toView:window];
    
    if (CGRectContainsRect(superViewRect,selfRect)) {//完全包含
        return;
    }else{//不完全包含
        NSMutableArray *rectArr = [NSMutableArray arrayWithArray:[superview enlargedRect]];
        CGRect newRect = CGRectMake(rect.origin.x - superViewRect.origin.x, rect.origin.y - superViewRect.origin.y, rect.size.width, rect.size.height);
        
        CGRect newEnlargeRect = CGRectMake(newRect.origin.x-enlargeEdge.left, newRect.origin.y-enlargeEdge.top, newRect.size.width+enlargeEdge.left+enlargeEdge.right, newRect.size.height+enlargeEdge.top+enlargeEdge.bottom);
        
        [rectArr addObject:NSStringFromCGRect(newEnlargeRect)];
        objc_setAssociatedObject(superview, &key_yjn_enlarged, rectArr, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

        [self freeView:superview.superview rect:rect enlargeEdge:enlargeEdge];
    }
}

3、响应者链传递

#pragma mark - 响应者链
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
    for (NSString *edgeStr in [self enlargedRect]) {
        CGRect rect= CGRectFromString(edgeStr);
        if (CGRectContainsPoint(rect,point)) {
            return YES;
        }
    }
    return NO;
}

-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
    // 1.判断下窗口能否接收事件
    if (self.userInteractionEnabled == NO || self.hidden == YES ||  self.alpha <= 0.01){
        return nil;
    }
    // 2.判断下点在不在窗口上
    // 不在窗口上
    if ([self pointInside:point withEvent:event] == NO){
        return nil;
    }

    // 3.从后往前遍历子控件数组
    int count = (int)self.subviews.count;
    for (int i = count - 1; i >= 0; i--)     {
        // 获取子控件
        UIView *childView = self.subviews[i];
        // 坐标系的转换,把窗口上的点转换为子控件上的点
        // 把自己控件上的点转换成子控件上的点
        CGPoint childP = [self convertPoint:point toView:childView];
        UIView *fitView = [childView hitTest:childP withEvent:event];
        if (fitView) {
            // 如果能找到最合适的view
            return fitView;
        }
    }
    // 4.没有找到更合适的view,也就是没有比自己更合适的view
    return self;
}

4、【注】如果要挣脱束缚,请想把view加到父view上,如[self.view addSubview:view];后才能添加enlargeEdge属性,否则不生效。demo地址https://github.com/yinjining/hitEnlarged

相关文章

网友评论

  • 梁森的简书:扩大点击区域直接重写pointInside方法就行了吧
    宁静1致远:@梁森森 是的,原理差不多
  • alanim:你的这个类别是通过接管了 页面上所有的UIView试图的响应链,若仅仅是使用一个增大点击范围的话 未免有些大题小作。接管是图上所有的响应链难免会出现对某些未知不可控制的失误或者对性能的影响。
    宁静1致远:这块是对view响应者链的重写,基本准守响应链规则。如果出现不可控问题,我们可以在自己写的代码里重写响应者链,如果你在你的类中重写了响应者链,这个category的响应者链是不走的。目前我再我项目中用暂时没碰到问题,很期待你能在试用中帮我找到问题,我做进一步改进,谢谢!

本文标题:增加点击区域

本文链接:https://www.haomeiwen.com/subject/gujavftx.html