iOS 超出视图部分按钮响应

在iOS开发中会遇到一些设计样式,需要把按钮一部分悬空在父视图的上面,但是当我们点击该按钮时,超出了父视图的悬空部分不会响应该按钮的点击事件。

大概如图所示:


image.png

红色容器View1中有蓝色button 需要在View1视图外点击button仍然生效。关于响应者链的学习资料:
iOS响应者链、事件的传递
iOS响应者链彻底掌握

这篇博客中比较详细的描述了响应者链是怎样传递的以及Hit-Test 机制 是如何生效的。我就不描述其中的原理了,我们这边只分析代码:

- (void)viewDidLoad 
{
    UIView1 *view1 = [[UIView1 alloc] initWithFrame:CGRectMake(0, 0, 260, 100)];
    view1.backgroundColor = [UIColor redColor];
    [self.view addSubview:view1];
    
    UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(120, 50, 260, 100)];
    btn.backgroundColor = [UIColor blueColor];
    [btn addTarget:self action:@selector(btnClick)   
    forControlEvents:UIControlEventTouchUpInside];
    [view1 addSubview:btn];
}

- (void)btnClick
{
    NSLog(@"btn 被点击了");
}

在UIView1中重写 hitTest 方法


- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    NSLog(@"View1 hitTest start ");
    UIView *item = [super hitTest:point withEvent:event];
    if (item == nil) { // 超出屏幕外的部分
        __block UIButton *btn = nil;
        // 先检查subviews 里的视图
        [self.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([obj isKindOfClass:[UIButton class]]) {
                // 找到需要处理的btn
                btn = (UIButton *)obj;
                *stop = YES;
            }
        }];
        
        // 当找到了对应的处理btn
        if (btn) {
            // 转换坐标系
            CGPoint p = [self convertPoint:point toView:btn];
            // 判断触摸点是否在button上
            if (CGRectContainsPoint(btn.bounds, p)) {
                item = [btn hitTest:p withEvent:event];
            }
        }
    }
    NSLog(@"View1 hitTest - %@",item);
    return item;
}

在点击超出原视图外的部分时,判断该点上有没有响应的子视图,如果没有,就再判断一下该点是不是在点击的这个按钮的视图坐标范围内,如果是响应该点击事件。

你可能感兴趣的:(iOS 超出视图部分按钮响应)