iOS 之事件

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;
    
}

注意:如果在判斷的時候是 子控件 需要轉化子控件的 坐標點

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容