事件傳遞響應總結

事件的產生和傳遞

  1. 發(fā)生觸摸事件后,系統(tǒng)會將該事件加入到一個由UIApplication管理的事件隊列中;
  2. UIApplication 會從事件隊列中取出最前面的事件,并將事件分發(fā)下去以便處理,通常,先發(fā)送事件給應用程序的主窗口keyWindow;
  3. 主窗口會在視圖層次結構中找到一個最合適的視圖來處理觸摸事件,這也是整個事件處理過程的第一步;
  4. 找到合適的視圖控件后,就會調用視圖控件的touches方法來作具體的事件處理。

UIView不接收觸摸事件的三種情況

  1. 不接收用戶交互 userInteractionEnabled = NO
  2. 隱藏 hidden = YES
  3. 透明 alpha = 0.0 ~ 0.01

提示: UIImageView 的 userInteractionEnabled默認就是NO,因此 UIImageView 以及它的子控件默認是不能接收觸摸事件的。

view中跟事件傳遞相關的三個方法

// 什么時候調用:當事件傳遞給當前view時,會調用當前view的hitTest方法。
// 作用:尋找最適合的view
// 返回值:返回誰,誰就是最適合的view,誰就響應事件,就會調用誰的touches方法

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    // 1. 判斷自己能否接收事件
    // 2. 點在不在自己身上
    // 3. 從后往前遍歷自己的子控件,把事件傳遞給子控件,調用子控件的hitTest,
   // 4. 如果子控件沒有找到最適合的view,那么自己就是最適合的view。
    return [super hitTest:point withEvent: event];
}

// 作用:點在不在自己身上,調用當前view一個方法(pointInside:)
// 什么時候調用:在hitTest內部調用的
// 返回值:YES 在當前view身上,NO 不在
// point: 當前觸摸點
// 注意:必須得要跟方法調用者在同一個坐標系
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
      return YES;
}
// touchesBegan 方法的默認做法是將事件順著響應者鏈條向上傳遞,將事件交給上一個響應者進行處理
// 就會調用上一個響應者的touches方法
// 上一個響應者是誰?先看當前view是否為控制器的view,如果是,那么上一個響應者就是他所在的控制器,如果不是,上一個響應者就是他的父控件。
// 千辛萬苦找到你這個view,但是如果沒有處理,那么就按照默認來
- (void)touchesBegin:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"%@----touch", [self class]);
}

自己實現(xiàn)hitTest:withEvent:方法

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

    // 3. 從后往前遍歷自己的子控件,把事件傳遞給子控件,調用子控件的hitTest
    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 *fitView = [childView hitTest:childP withEvent: event];
        if (fitView) {
            return fitView;
        }
    }
    // 4. 如果子控件沒有找到最適合的view,那么自己就是最適合的view
    return self;
}

傳遞和響應是兩個過程

完整過程如下

  1. 先將事件對象由上往下傳遞(由父控件傳遞給子控件),找到最合適的控件來處理這個事件;
  2. 調用最合適控件的touches...方法;
  3. 如果調用了[super touches...];就會將事件順著響應者鏈條往上傳遞,傳遞給上一個響應者;
  4. 接著就會調用上一個響應者的touches...方法

如何判斷上一個響應者

  1. 如果當前這個view是控制器的view,那么控制器就是上一個響應者;
  2. 如果當前這個view不是控制器的view,那么父控件就是上一個響應者。

備注

視頻鏈接-第五章上
參考文章,也是看過那個視頻寫出來的

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

相關閱讀更多精彩內容

友情鏈接更多精彩內容