iOS的事件分類
-
1 觸摸事件(是開發(fā)中經(jīng)常使用的事件)
- 只有繼承
UIResponder的對象才能處理事件,對之做出響應,也稱為響應者對象 -
UIApplication,UIView,UIViewController都是繼承UIResponder,都可以處理事件
- 只有繼承
-
2 加速計事件(搖一搖,跑步計數(shù)等)
-
3 遠程控制事件(耳機切換歌曲)
觸摸事件處理的的方法
- 開始觸摸
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
- 移動
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
- 取消
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
- 結束
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
UITouch觸摸對象常用的方法和屬性
- 方法
-1 - (CGPoint)locationInView:(nullable UIView *)view; 返回當前觸摸對象的View的坐標點
-2 - (CGPoint)previousLocationInView:(nullable UIView *)view;返回當前觸摸View的上一次的觸摸點
- 屬性
@property(nonatomic,readonly) NSTimeInterval timestamp;
@property(nonatomic,readonly) UITouchPhase phase;
@property(nonatomic,readonly) NSUInteger tapCount; // touch down within a certain point within a certain amount of time
@property(nonatomic,readonly) UITouchType type
demo例子(UIView的拖拽)
給控制器,添加一個子控件
UIView,在UIView中實現(xiàn) 觸摸事件的處理方法
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//獲取到UITouch對象
UITouch *touch = [touches anyObject];
//當前的觸摸點
CGPoint currentPoint = [touch locationInView:self];
//獲取到上一次移動的觸摸點
CGPoint prePoint = [touch previousLocationInView:self];
//移動的差值
CGFloat offsetX = currentPoint.x - prePoint.x;
CGFloat offsetY = currentPoint.y - prePoint.y;
//平移(transform), 在原來平移的基礎上平移
self.transform = CGAffineTransformTranslate(self.transform, offsetX, offsetY);
}

01_uiview的平移.gif
事件的傳遞
- 發(fā)生觸摸事件之后,系統(tǒng)會將改事件加入到
UIApplication管理的事件隊列中 -
UIApplication會從事件隊列中取出最前面的事件,并將改事件分發(fā)給keyWindow處理 - 主窗口(keyWindow)會在視圖層中找到一個最合適的視圖來處理這個事件
- 當找到
合適的View控件之后,就會調用觸摸事件的touches方法 做出相應的事件處理
注意: 事件的傳遞的一層一層的,從父控件傳遞給子控件,如果父控件不能接受事件的傳遞,那么子控件也就不能接受觸摸事件

02.png
當點擊
綠色的View事件的傳遞過程為
UIApplication->UIWindow->粉色View->紫色View->綠色View
- 不能接受事件的3中情況
//1.控件的屬性,不可以交互的
userInteractionEnabled = no
//2.隱藏控件
hidden = yes
//3.透明度小于 0.01的控件
//上述的3中情況,不可以處理事件
尋找最合適的View處理事件
操作判斷
- 1.判斷是否可以處理事件
- 2.觸摸點是否在自己身上
- 3.重后向前遍歷,執(zhí)行1,2的操作尋找子控件
- 4.如果沒有,則自己就是最合適的view
需要實現(xiàn)的方法
//一個事件傳遞給這個View的時候,這個方法就會被調用
//返回的值,就是最合適的View
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
return [super hitTest:point withEvent:event];
}
//判斷當前點是不是在自己身上
//當hitTest:withEvent:調用的時候,內(nèi)部就會調用這個方法
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event{
return YES;
}
hitTest: withEvent:方法的內(nèi)部原理實現(xiàn)
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
//內(nèi)部實現(xiàn)方法
//1.判斷是否可以接受事件
if (self.hidden == YES || self.alpha <= 0.01 || self.userInteractionEnabled == NO) {
return nil;
}
//2.判斷觸摸點是否在自己身上
if (![self pointInside:point withEvent:event]) {
return nil;
}
//3.從后向前遍歷子控件
int count = (int)self.subviews.count;
for (int i = count - 1; i >= 0; i--) {
//獲取到子控件
UIView *chiledView = self.subviews[i];
//轉化坐標點 到子控件上
CGPoint childPoint = [self convertPoint:point toView:chiledView];
//獲取View
UIView *fitView = [chiledView hitTest:childPoint withEvent:event];
//如果存在,就是最合適的view
if (fitView) {
return fitView;
}
}
//沒有找到合適的View,返回自己
return self;
}
注意:如果在判斷的時候是 子控件
需要轉化子控件的 坐標點