iOS開發事件分發機制—響應鏈—手勢影響

一、提綱html

  • 什麼是iOS的事件分發機制 ?
  • 一個事件UIEvent又是如何響應的?
  • 手勢對於響應鏈有何影響?

 

二、事件分發機制app

  2.一、來源ide

    以直接觸摸事件爲例:spa

    1. 當用戶一個手指觸摸屏幕是會生成一個UITouch對象,多個手指就是多個對象,手指移動系統會更新對象的相應信息。
    2. 系統會將UITouch對象封裝生成一個事件UIEvent對象,將這個事件交給最佳具備響應能力的視圖處理。
    3. 系統有個UIResponder類,只有繼承UIResponder的類才具備響應事件能力,因此UIKit系統控件大可能是繼承此類。

    如何找處處理這個事件的視圖的過程——事件分發機制代理

  2.二、具體步驟code

    2.2.一、事件Event的產生htm

      點擊一下iOS設備的屏幕,UIKit就會生成一個事件對象UIEvent,而後會把這個Event分發給當前活動的app; 對象

      當前活動的app得知有事件,UIApplication 單例就會從事件隊列中去取最新的事件,而後分發給可以處理該事件的對象(具體視圖)。blog

    2.2.二、運用到的兩個UIView中的方法繼承

- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;   //找到並返回最合適的視圖來
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;   //判斷點是否在視圖內

      當一個視圖View收到hitTest消息時,會調用本身的poinInside方法;

      若是返回YES,View會遍歷本身的子視圖(遍歷順序先addSubView先遍歷),子視圖就會調用本身的hitTest方法;

      若是返回NO,View就不會遍歷本身子視圖(很節約);

      直到找到最小的可以處理事件的view,若是整了一圈沒找到可以處理的view,則返回自身。

    2.2.三、舉例說明

      白色:ViewController , 綠色:一個View視圖  , 藍色:一個Button按鈕

      現象:點擊綠色視圖內的按鈕區域,正常;點擊綠色視圖外的按鈕區域,按鈕的selector方法不會調用?

      從新綠色view的hitTest方法:

      點擊有效區域時:返回視圖座標{{88, -26}, {47, 52}},此座標是相對父視圖的;

      點擊區域外的部分時:返回視圖座標{{0, 0}, {0, 0}},因此按鈕不會響應;

      從新hitTest方法,修改返回view,當點擊區域外按鈕部分時也返回有效視圖{{88, -26}, {47, 52}},如圖所示;

      另一種解決方案:更暴力 

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
    return YES;
}

號外:

  若是 View 的 userInteractionEnabled = NO,enabled = NO( UIControl ),或者 alpha <= 0.01, hidden = YES 等狀況的時候,直接返回 nil。
  若是觸摸點不在 view 中,直接返回 nil (例子就是此現象)。


三、響應鏈
  響應鏈:在事件分發機制尋找view時會生成響應鏈;
  第一響應者:上例中Button就是第一響應者;
  下一個響應者:UIResponder有個屬性只讀的爲nextResponder,當第一響應者不處理事件時就在吧事件拋給下一個響應者;
  響應鏈的一些規則:
1. UIView 的 nextResponder 是直接管理它的 UIViewController (也就是 VC.view.nextResponder = VC ),若是當前 View 不是 ViewController 直接管理的 View,則 nextResponder 是它的 superView( view.nextResponder = view.superView )。
2. UIViewController 的 nextResponder 是它直接管理的 View 的 superView( VC.nextResponder = VC.view.superView )。
若是viewcontroller的view是window的根view,那麼下一個響應者是window;
若是viewcontroller是另外一個viewcontroller模態推出的,那麼下一個響應者是另外一個viewcontroller;
若是viewcontroller的view被add到另外一個viewcontroller的根view上,那麼下一個響應者是另外一個viewcontroller的根view
3. UIWindow 的 nextResponder 是 UIApplication 。
4. UIApplication 的 nextResponder 是 AppDelegate。
  上例中的響應鏈:UIButton.nextResponder = 綠色view.nextResponder = VC.view.nextResponder = VC.nextResponder = VC.view.superViewe(本例中爲UIWindow).nextResponder = UIApplication.nextResponder = AppDelegate ;

   通常來講,某個 UIResponder 的子類想要本身處理一些事件,就須要重寫它的這些方法(觸摸爲例):

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch *> *)touches NS_AVAILABLE_IOS(9_1);

  若是想本身處理後,繼續讓事件響應下去:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
}

- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
}

 

四、手勢對響應鏈有何影響

  手勢識別器並非響應者鏈中的一員,可是手勢識別器會觀察touch事件,並延遲事件向所綁定的視圖傳遞;

  在上例中給Button和view添加點擊手勢:

  按鈕會優先響應手勢,而不是自身的selector;

  設置手勢代理:讓按鈕響應自身的selector
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
    if ([touch.view isKindOfClass:[UIButton class]]) {
        return NO;
    }else{
        return YES;
    }
}

  

  添加手勢又屏蔽:有毛病?

  在其餘UICollectionView和UIScrollView、UITableView等,若是須要在視圖上添加手勢,cell上也會響應手勢,此方法能夠解決手勢和自身方法的衝突!

 
相關文章
相關標籤/搜索