美文网首页iOS开发iOS 开发每天分享优质文章
iOS点击事件穿透及扩大视图点击区域

iOS点击事件穿透及扩大视图点击区域

作者: 神SKY | 来源:发表于2018-05-02 15:28 被阅读480次

    前言

    点击事件穿透指的是点击当前视图,但是实际上被选中的是其他视图。举个例子,下方效果图中有两个按钮,当点击不重合的地方,显示的是点击当前视图,当点击重合地方时,点击的是下方的视图。


    点击事件扩大区域指的是点击当前视图区域外的位置,仍然显示的是点击当前视图。举个例子,下方效果图中黄色部分是按钮,红色部分是按钮外的区域,但是点击红色部分,仍能显示点击黄色按钮。

    说到这里,应该对这两种效果有一个初步的理解了。那这两种效果是怎么实现的呢?这两种效果是基于系统的SDK- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event实现的。这个方法是UIView的一个实例方法,官方的注释如下:

    recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system

    意思是这个方法会递归调用-pointInside:withEvent:这个方法,point是接收者的坐标系,也就是点击的这个点在视图中的相对坐标。

    点击事件穿透

    实现点击事件穿透的本质是在视图中判断点击的点是否属于你想要点击的视图,然后判断返回相应的视图即可。
    在这里,附上上方效果做法。
    自定义按钮视图,并放置一个可传入的按钮。如下:

    #import <UIKit/UIKit.h>
    
    @interface RedButton : UIButton
    @property (strong, nonatomic) UIButton *button;
    
    @end
    
    #import "RedButton.h"
    
    @interface RedButton()
    
    @end
    
    @implementation RedButton
    
    - (instancetype)initWithFrame:(CGRect)frame {
        if (self = [super initWithFrame:frame]) {
            self.backgroundColor = [UIColor redColor];
            self.layer.masksToBounds = YES;
            self.layer.cornerRadius = frame.size.width / 2;
        }
        return self;
    }
    
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    {
        CGPoint redPoint = [self convertPoint:point toView:self.button];
        if ([self.button pointInside:redPoint withEvent:event]) {
            return self.button;
        }else {
            return [super hitTest:point withEvent:event];
        }
    }
    @end
    

    设置UI和点击方法,如下:

    #pragma mark 点击事件穿透
    - (void)setUpSubViewToThrough {
        
        CGFloat blue_width = screen_width / 3;
        CGFloat blue_height = blue_width;
        CGFloat blue_x = (screen_width - blue_width * 2) / 2;
        CGFloat blue_y = (screen_height - blue_height * 2) / 2;
        UIButton *blue = [[UIButton alloc]init];
        [blue setFrame:(CGRect){blue_x, blue_y, blue_width, blue_height}];
        [blue setBackgroundColor:[UIColor blueColor]];
        [blue addTarget:self action:@selector(blueButtonAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:blue];
        
        CGFloat red_width = screen_width / 2;
        CGFloat red_height = red_width;
        CGFloat red_x = blue_x * 2;
        CGFloat red_y = (screen_height - blue_height) / 2;
        RedButton *red = [[RedButton alloc]initWithFrame:(CGRect){red_x, red_y, red_width, red_height}];
        [red addTarget:self action:@selector(redButtonAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:red];
        
        red.button = blue;
    }
    
    - (void)blueButtonAction:(UIButton *)sender {
        NSLog(@"点击蓝按钮");
    }
    
    - (void)redButtonAction:(UIButton *)sender {
        NSLog(@"点击红按钮");
    }
    

    扩大视图点击区域

    扩大视图点击区域的本质是判断所点击的点是否在于你想要扩大的区域上。在这里,楼主所设置的扩大区域是边线外增加30。实现如下,自定义视图:

    #import <UIKit/UIKit.h>
    
    @interface YellowButton : UIButton
    
    @end
    
    #import "YellowButton.h"
    
    @interface YellowButton()
    
    @end
    
    @implementation YellowButton
    
    - (instancetype)initWithFrame:(CGRect)frame
    {
        if (self == [super initWithFrame:frame]) {
            self.backgroundColor = [UIColor yellowColor];
        }
        return self;
    }
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    {
        CGFloat min_x = -30.0;
        CGFloat min_y = -30.0;
        CGFloat max_x = self.frame.size.width + 30;
        CGFloat max_y = self.frame.size.height + 30;
        
        if (point.x <= max_x && point.x >= min_x && point.y <= max_y && point.y >= min_y) {
            point = CGPointMake(0, 0);
            return [super hitTest:point withEvent:event];
        }else {
            return [super hitTest:point withEvent:event];
        }
        
    }
    @end
    

    设置UI和点击方法,如下:

    #pragma mark 扩大点击区域
    - (void)setUpSubViewToArea {
        
        CGFloat yellow_width = screen_width / 3;
        CGFloat yellow_height = yellow_width;
        CGFloat yellow_x = (screen_width - yellow_width) / 2;
        CGFloat yellow_y = (screen_height - yellow_height) / 2;
        YellowButton *yellow = [[YellowButton alloc]initWithFrame:(CGRect){yellow_x, yellow_y, yellow_width, yellow_height}];
        [yellow addTarget:self action:@selector(yellowButtonAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:yellow];
        
        CGFloat backgroundView_width = yellow_width + 60;
        CGFloat backgroundView_height = backgroundView_width;
        CGFloat backgroundView_x = yellow_x - 30;
        CGFloat backgroundView_y = yellow_y - 30;
        UIView *backgroundView = [[UIView alloc]initWithFrame:(CGRect){backgroundView_x, backgroundView_y, backgroundView_width, backgroundView_height}];
        backgroundView.backgroundColor = [UIColor redColor];
        [self.view insertSubview:backgroundView belowSubview:yellow];
    }
    
    - (void)yellowButtonAction:(UIButton *)sender {
        NSLog(@"点击黄按钮");
    }
    

    希望这篇文章对各位看官有所帮助,Demo下载地址:Demo

    相关文章

      网友评论

        本文标题:iOS点击事件穿透及扩大视图点击区域

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