事件产生传递及底层实现
1.事件基础知识
- 1.ios当中常用的事件?
- 触摸事件
- 加速计事件
- 远程控制事件
-
2.什么是响应者对象?
- 继承了UIResponds的对象我们称它为响应者对象
- UIApplication、UIViewController、UIView都继承自UIResponder
- 因此它们都是响应者对象,都能够接收并处理事件
-
3.为什么说继承了UIResponder就能够处理事件?
因为UIResponder内部提供了以下方法来处理事件
比如触摸事件会调用以下方法:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; - ()void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesCancelled:(NSSet *)touches withEvent: (UIEvent *)event;
**加速计事件**会调用:
```
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;
```
**远程控制事件**会调用:
```
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;
```
- 4.如何监听UIView的触摸事件?
想要监听UIViiew的触摸事件,首先第一步要自定义UIView,
因为只有实现了UIResponder的事件方法才能够监听事件.
UIView的触摸事件主要有:
一根或者多根手指开始触摸view,系统会自动调用view的下面方法.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
一根或者多根手指在view上移动时,系统会自动调用view的下面方法
(随着手指的移动,会持续调用该方法,也就是说这个方法会调用很多次)
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
一根或者多根手指离开view,系统会自动调用view的下面方法
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
#### 2.UIView拖拽思路?
- 1.自定义UIView,实现监听方法.
- 2.确定在TouchMove方法当中进行操作,因为用户手指在视图上移动的时候才需要移动视图。
- 3.获取当前手指的位置和上一个手指的位置.
- 4.当前视图的位置 = 上一次视图的位置 - 手指的偏移量
实现关键代码:
当手指在屏幕上移动时调用持续调用
NSSet:里面的元素都是无序的.
NSArray:里面的有顺序的.
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
1.获取手指的对象
UITouch *touch = [touches anyObject];
2.获取当前手指所在的点.
CGPoint curP = [touch locationInView:self];
3.获取手指的上一个点.
CGPoint preP = [touch previousLocationInView:self];
X轴方向偏移量
CGFloat offsetX = curP.x - preP.x;
Y轴方向偏移量
CGFloat offsetY = curP.y - preP.y;
CGAffineTransformMakeTranslation:会清空上一次的形变.
self.transform = CGAffineTransformMakeTranslation(offsetX, 0);
self.transform = CGAffineTransformTranslate(self.transform, offsetX, offsetY);
}
#### 3.事件的产生与传递
- 事件是怎么样产生与传递的?
- 当发生一个触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中.
- UIApplication会从事件队列中取出最前面的事件,交给主窗口.
- 主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件
- 触摸事件的传递是从父控件传递到子控件的.
- 如果一个父控件不能接收事件,那么它里面的了子控件也不能够接收事件.
- 一个控件什么情况下不能够接收事件?
- 1.不接收用户交互时不能够处理事件
userInteractionEnabled = NO
- 2.当一个控件隐藏的时候不能够接收事件
Hidden = YES的时候
- 3.当一个控件为透明白时候也不能够接收事件
注意:UIImageView的userInteractionEnabled默认就是NO,因此UIImageView以及它的子控件默认是不能接收触摸事件的
- 如何寻找最合适的View?(**重点**)
- 1.先判断自己是否能够接收触摸事件,如果能再继续往下判断,
- 2.再判断触摸的当前点在不在自己的身上.
- 3.如果在自己身上,它会从后往前遍历子控件,遍历出每一个子控件后,重复前面的两个步骤.
- 4.如果没有符合条件的子控件,那么它自己就是最适合的View.
#### 4.底层实现
- hitTest方法
- 作用:寻找最适合的View
- 参数:当前手指所在的点.产生的事件
- 返回值:返回谁, 谁就是最适合的View.
- 什么时候用调用:只要一个事件,传递给一个控件时, 就会调用这个控件的hitTest方法
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
- PointInside方法
- 作用:判断point在不在方法调用者上
- point:必须是方法调用者的坐标系
- 什么时候调用:hitTest方法底层会调用这个方法,判断点在不在控件上.
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
return YES;
}
- hitTest方法底层实现
- 作用:当一个事件传递给当前View的时候就会调用这个方法.
- 当前手指在屏幕上的点
- 当前产生的事件
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
1.查看自己能不能接收事件
if(self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01){
return nil;
}
2.判断当前的点在不在自己身上.
if(![self pointInside:point withEvent:event]){
return nil;
}
查看自己是不是最适合的view
从后往前遍历自己的子控制器.
int count = (int)self.subviews.count;
for (int i = count - 1; i >=0; i--) {
取出子控制器.
UIView *childView = self.subviews[i];
要把当前的点转换成子控件上的坐标点.
CGPoint childP = [self convertPoint:point toView:childView];
UIView *view = [childView hitTest:childP withEvent:event];
如果有值,直接返回,返回的就是最适合的View.
if (view) {
return view;
}
}
没有找到比自己更适合的View.自己就是最适合的View
return self;
}














网友评论