美文网首页iOS-深入UI
第二篇:CALayer能力之hitTest响应事件

第二篇:CALayer能力之hitTest响应事件

作者: 意一ineyee | 来源:发表于2018-01-22 17:07 被阅读171次

    目录

    一、CALayer hitTest响应事件

    二、UIView hitTest+pointInside判断点击的点是否在某个区域内,由指定的视图响应事件


    • 首先我们明确CALayer的hitTest和UIView的hitTest它俩不一样,不是为了解决同样的问题,其实内在有关联,但是不想阐述了。就实际应用大概了解下就行,CALayer的hitTest是为了能让layer响应事件,而UIView的hitTest+pointInside是为了判断点击的点是否在某个区域内,从而让指定的视图响应事件。本篇只是表明CALayer也是有办法响应事件的,只不过如果自己维护事件会很麻烦。

    一、CALayer hitTest响应事件

    前面我们说到要优先使用UIView,因为UIView自己会处理用户交互,而CALayer则不关心用户交互,如果使用CALayer我们就得自己维护复杂的用户交互事件。
    例如,现在一个红色button上放了一个绿色button(绿色button完全在红色button内部),如果使用UIView的话,因为响应者链会优先让子视图响应事件,所以点了绿button部分绿button就响应事件,点了红button部分红button就响应事件,根本不存在疑惑。但是现在如果非要用layer,一个红色layer上放了一个绿色layer(绿色layer完全在红色layer内部),我们就只能通过layer的hitTest方法来判断点击的点是在那个layer的范围内,从而响应不同的事件。

    //
    //  ViewController.m
    //  CoreAnimation
    //
    //  Created by 意一yiyi on 2017/11/13.
    //  Copyright © 2017年 意一yiyi. All rights reserved.
    //
    
    #import "ViewController.h"
    
    @interface ViewController ()
    
    @property (strong, nonatomic) UIView *redView;
    @property (strong, nonatomic) UIView *greenView;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.redView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
        self.redView.backgroundColor = [UIColor redColor];
        [self.view addSubview:self.redView];
        
        self.greenView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
        self.greenView.backgroundColor = [UIColor greenColor];
        [self.redView addSubview:self.greenView];
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        
        // 获取[UIApplication sharedApplication].delegate.window坐标系下点击的点
        CGPoint point = [[touches anyObject] locationInView:[UIApplication sharedApplication].delegate.window];
        
        // 在[UIApplication sharedApplication].delegate.window坐标系下,点击了某个点point,返回point所在的layer
        CALayer *layer = [[UIApplication sharedApplication].delegate.window.layer hitTest:point];
        if (layer == self.redView.layer) {
    
            NSLog(@"点击了红色区域");
        }else if (layer == self.greenView.layer) {
    
            NSLog(@"点击了绿色区域");
        }
    }
    
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    

    二、UIView hitTest+pointInside判断点击的点是否在某个区域内,由指定的视图响应事件

    1、问题:

    开发中我们会发现,如果一个子视图超出了父视图的边界,那么子视图超出父视图边界的部分将是不能响应事件的,例如直播的那个中间突出的按钮,那怎么办呢?先看例子:

    //
    //  CustomView.m
    //  CoreAnimation
    //
    //  Created by 意一yiyi on 2017/12/18.
    //  Copyright © 2017年 意一yiyi. All rights reserved.
    //
    
    #import "CustomView.h"
    
    @interface CustomView ()
    
    @property (strong, nonatomic) UIButton *redButton;
    @property (strong, nonatomic) UIButton *greenButton;
    
    @end
    
    @implementation CustomView
    
    - (instancetype)initWithFrame:(CGRect)frame {
        
        if (self = [super initWithFrame:frame]) {
            
            [self layoutUI];
        }
        
        return self;
    }
    
    - (void)layoutUI {
        
        self.frame = CGRectMake(150, 150, 200, 200);
        
        self.redButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
        self.redButton.backgroundColor = [UIColor redColor];
        [self.redButton addTarget:self action:@selector(redButtonAction) forControlEvents:(UIControlEventTouchUpInside)];
        [self addSubview:self.redButton];
        
        self.greenButton = [[UIButton alloc] initWithFrame:CGRectMake(-50, -50, 100, 100)];
        self.greenButton.backgroundColor = [UIColor greenColor];
        [self.greenButton addTarget:self action:@selector(greenButtonAction) forControlEvents:(UIControlEventTouchUpInside)];
        [self.redButton addSubview:self.greenButton];
    }
    
    - (void)redButtonAction {
        
        NSLog(@"点击了红色区域");
    }
    
    - (void)greenButtonAction {
        
        NSLog(@"点击了绿色区域");
    }
    
    @end
    
    1.png

    点击超出红色区域的绿色部分,我们会发现控制台确实是不打印东西的。

    2、解决:

    那这时我们就需要重写一下UIView的- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event方法来实现这一效果,其中最核心的部分就是通过UIView或者CALayer来判断点击点是否在指定的区域内。这个方法的作用就是告诉系统当我们点击了屏幕的时候,由谁来响应事件。

    我们在CustomView.m里面添加如下代码就可以了:

    // UIView判断点击的点是否在指定区域内
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
            
        // 需要先把点击的点转换到greenButton坐标系下
        CGPoint newPoint = [self convertPoint:point toView:self.greenButton];
        
        // 判断点击点是否在greenButton上
        if ([self.greenButton pointInside:newPoint withEvent:event]) {// 在的话,由自定义greenButton来响应事件
            
            return self.greenButton;
        }else {// 否则由系统自己处理
            
            return [super hitTest:point withEvent:event];
        }
    }
    

    相关文章

      网友评论

        本文标题:第二篇:CALayer能力之hitTest响应事件

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