事件传递

事件传递_第1张图片
屏幕快照 2016-05-25 上午11.01.37.png

事件传递_第2张图片
屏幕快照
事件传递_第3张图片
屏幕快照 2016-05-25 上午11.02.49.png

最合适响应view:当点击一个view时,她首先将事件传递给UIApplication, UIApplication->UIWindow->控制器view->父视图->子视图->点击view
touches方法的默认做法是将事件顺着响应者链条向上传递,将事件交给上一个响应者进行处理。

一个View是如何判断自己为最佳处理点击事件的View

// recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;

// default returns YES if point is in bounds
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;

- hitTest: withEvent:方法的底层实现

此底层实现说明了, 一个view的子控件是如何判断是否接收点击事件的.

此方法返回的View是本次点击事件需要的最佳View

// 因为所有的视图类都是继承BaseView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
//    NSLog(@"%@--hitTest",[self class]);
//    return [super hitTest:point withEvent: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.从后往前遍历自己的子控件
    NSInteger count = self.subviews.count;

    for (NSInteger 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;
        }


    }

    // 循环结束,表示没有比自己更合适的view
    return self;

}

根据以上的实现, 那么我们就可以重写这个方法, 做一些非常规的效果

此方法返回的View是本次点击事件需要的最佳View

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{

    // 当前控件上的点转换到chatView上
    CGPoint chatP = [self convertPoint:point toView:self.chatView];

    // 判断下点在不在chatView上
    if ([self.chatView pointInside:chatP withEvent:event]) {
        return self.chatView;
    }else{
        return [super hitTest:point withEvent:event];
    }

}

你可能感兴趣的:(事件传递)