1.如何寻找最合适的View接收触摸事件?
主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件.
那如何找到最合适的View呢?
1.先判断自己是否能够接收触摸事件,如果能再继续往下判断,
2.再判断触摸的当前点在不在自己的身上.
3.如果在自己身上,它会从后往前遍历子控件,遍历出每一个子控件后,重复前面的两个步骤.
4.如果没有符合条件的子控件,那么它自己就是最适合的View.
2.用hitTest方法寻找最合适的View
hitTest⽅方法
作用:寻找最适合的View
参数:当前手指所在的点.产生的事件
返回值:返回谁, 谁就是最适合的View. 什么时候⽤调⽤:只要⼀一个事件,传递给⼀一个控件时, 就会调用这个控件的hitTest⽅法
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
PointInside⽅方法
作用:判断point在不在方法调用者上 point:必须是方法调⽤用者的坐标系 什么时候调⽤:hitTest⽅法底层会调用这个方法,判断点在不在控件上.
//作用:判断当前点在不在它调用View,(谁调用pointInside,这个View就是谁) //什么时候调用:它是在hitTest方法当中调用的. //注意:point点必须得要跟它方法调用者在同一个坐标系里面 -(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{ NSLog(@"%s",__func__); return YES; }
hitTest⽅法底层实现
作用:当一个事件传递给当前View的时候就会调用这个⽅法. 当前⼿指在屏幕上的点
当前产生的事件
//作用:去寻找最适合的View //什么时候调用:当一个事件传递给当前View,就会调用. //返回值:返回的是谁,谁就是最适合的View(就会调用最适合的View的touch方法) -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ //1.判断自己能否接收事件 if(self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) { return nil; } //2.判断当前点在不在当前View. if (![self pointInside:point withEvent:event]) { return nil; } //3.从后往前遍历自己的子控件.让子控件重复前两步操作,(把事件传递给,让子控件调用hitTest) int count = (int)self.subviews.count; for (int i = count - 1; i >= 0; i--) { //取出每一个子控件 UIView *chileV = self.subviews[i]; //把当前的点转换成子控件从标系上的点. CGPoint childP = [self convertPoint:point toView:chileV]; UIView *fitView = [chileV hitTest:childP withEvent:event]; //判断有没有找到最适合的View if(fitView){ return fitView; } } //4.没有找到比它自己更适合的View.那么它自己就是最适合的View return self; }
3.hitTest练习
业务逻辑:
底部⼀一个按钮, 按钮的上⾯面有⼀一个View,遮挡在按钮的上⾯面.
点击View时, View接收事件,当发现点击的点在按钮的位置时, 让底部的按钮处理事件.
实现思路:
实现View的touchBegain方法,先监听UIView的点击.
并去实现UIView的HitTest方法, 在hitTest⽅法当中通过把当前点转换成按钮所在的坐标系
CGPoint btnP = [self convertPoint:point toView:self.btn];
转换过后查看当前点在不在按钮上,如果在按钮上,就直接返回按钮.
如果有在按钮上,保持系统默认做法.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ //NSLog(@"%@",self.btn); //return [super hitTest:point withEvent:event]; //拿到后面的按钮 //当点在按钮上的时候,才返回按钮,如果不在按钮上.保持系统默认做法 //判断点在不在按钮身上 //把当前的点转换到按钮身上的坐标系的点 CGPoint btnP = [self convertPoint:point toView:self.btn]; if ([self.btn pointInside:btnP withEvent:event]) { return self.btn; }else{ return [super hitTest:point withEvent:event]; } }