獲取當前viewcontroller響應事件傳遞


通過UIViewController的view屬性可以訪問到其管理的view對象,及此view的所有subviews。但是根據一個view對象,沒有直接的方法可以得到管理它的viewController,但我們使用responder chain可以間接的得到

-(UIViewController*)parentController{
    UIResponder *responder = [self nextResponder];
    while (responder) {
    if ([responder isKindOfClass:[UIViewController class]]) {
        return (UIViewController*)responder;
    }
    responder = [responder nextResponder];
    }
    return nil;
}

或者以下方法
//獲取當前屏幕顯示的viewcontroller
- (UIViewController *)getCurrentVC
{
    UIViewController *result = nil;
    
    UIWindow * window = [[UIApplication sharedApplication] keyWindow];
    if (window.windowLevel != UIWindowLevelNormal)
    {
        NSArray *windows = [[UIApplication sharedApplication] windows];
        for(UIWindow * tmpWin in windows)
        {
            if (tmpWin.windowLevel == UIWindowLevelNormal)
            {
                window = tmpWin;
                break;
            }
        }
    }
    
    UIView *frontView = [[window subviews] objectAtIndex:0];
    id nextResponder = [frontView nextResponder];
    
    if ([nextResponder isKindOfClass:[UIViewController class]])
        result = nextResponder;
    else
        result = window.rootViewController;
    
    return result;
}

2.獲取當前屏幕中present出來的viewcontroller。

- (UIViewController *)getPresentedViewController
{
    UIViewController *appRootVC = [UIApplication sharedApplication].keyWindow.rootViewController;
    UIViewController *topVC = appRootVC;
    if (topVC.presentedViewController) {
        topVC = topVC.presentedViewController;
    }
    
    return topVC;
}




[[self superview ].nextResponder method];
[[[self superview ] nextResponder] method];
[self.nextResponder method];

官方文檔中的解釋

UIView implements this method by returning the UIViewController object that manages it (if it has one) or its superview (if it doesn’t); UIViewController implements the method by returning its view’s superview; UIWindow returns the application object, and UIApplication returns nil.


也就是說響應事件是一層一層進行傳遞的


當用戶 與 iPhone的觸摸屏 產生 互動時,硬件 就會探測到 物理接觸 並且 通知 操作系統。接着 操作系統 就會創建 相應的事件 並且 將 其 傳遞給 當前正在運行的應用程序的事件隊列。然後 這項事件 會被事件循環 傳遞給 優先響應者物件。優先響應者物件 是 事件 被觸發時 和 用戶 交互的物件,比如 按鈕物件、視圖物件。如果 我們 編寫了 代碼 讓 優先響應者 處理 這種類型的事件,那麼 它 就會處理 這種類型的事件。處理完 某項事件後,響應者 有 兩個選項:1、將 其 丟棄;2、將 其 傳遞給 響應鏈條中的下一個響應者。下一個響應者的地址 存儲 在當前響應者物件所包含的變量nextResponder當中。如果 優先響應者 無法處理 一項事件,那麼 這項事件 就傳遞給 下一個響應者,直到 這項事件 到達 能處理它的響應者 或者 到達 響應鏈條的末端,也就是 UIApplication類型的物件。UIApplication類型的物件 收到 一項事件後,也是 要麼 處理,要麼 丟棄。

比如 有 一個視圖物件,這個視圖物件上 有 一個按鈕物件。當用戶 觸摸 這個按鈕物件時,作爲優先響應者,這個按鈕物件 就會收到 一項事件。如果 這個按鈕物件 無法處理 這項事件,就會將 這項事件 傳遞給 視圖物件。如果 視圖物件 無法處理 這項事件,就會將 這項事件 傳遞給 視圖控制器物件。以此類推。

應該注意的 是 當我們 在使用 響應鏈條時,一項事件 並不會自動地 從一個響應者 傳遞到 下一個響應者。如果 要將 一項事件 從一個響應者 傳遞到 下一個響應者,我們 必須編寫 代碼 才能辦到。



上文提到了responder chain,responder chain是一系列連接的responder對象,通過responder對象可以將處理事件的責任傳遞給下一個,更高級的對象,即當前responder對象的nextResponder。


  • UIView的nextResponder屬性,如果有管理此view的UIViewController對象,則爲此UIViewController對象;否則nextResponder即爲其superview。
  • UIViewController的nextResponder屬性爲其管理view的superview.
  • UIWindow的nextResponder屬性爲UIApplication對象。
  • UIApplication的nextResponder屬性爲nil。

    iOS系統在處理事件時,通過UIApplication對象和每個UIWindow對象的sendEvent:方法將事件分發給具體處理此事件的responder對象(對於觸摸事件爲hit-test view,其他事件爲first responder),當具體處理此事件的responder不處理此事件時,可以通過responder chain交給上一級處理。

    1. 如果hit-test view或first responder不處理此事件,則將事件傳遞給其nextResponder處理,若有UIViewController對象則傳遞給UIViewController,傳遞給其superView。
    2. 如果view的viewController也不處理事件,則viewController將事件傳遞給其管理view的superView。
    3. 視圖層級結構的頂級爲UIWindow對象,如果window仍不處理此事件,傳遞給UIApplication.
    4. 若UIApplication對象不處理此事件,則事件被丟棄。




即如下代碼可以進行判斷:

id next = [self nextResponder];
while(![next isKindOfClass:[ViewController class]])//這裏跳不出來。。。有人說這裏跳不出來,其實是因爲它沒有當前這個view放入ViewController中,自然也就跳不出來了,會死循環,使用時需要注意。
{
next = [next nextResponder];
}
if ([next isKindOfClass:[ViewController class]])
{
controller = (ViewController *)next;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章