2014-05-06 29 views
18

如果拖動UIViewController各地開始UINavigationController內的互動彈出的過渡中,UIViewController目前一個已經viewWillAppear:稱爲下方,其次是UINavigationControllerDelegate方法navigationController:willShowViewController:animated:取消互動的UINavigationController流行手勢不叫UINavigationControllerDelegate方法

如果您取消了轉換,按預期在頂部視圖控制器上調用了viewWillAppear:viewDidAppear:

但是,根本不調用代表方法navigationController:willShowViewController:animated:navigationController:didShowViewController:animated:

考慮到調用UIViewController視圖生命週期方法,至少應該調用其中的一個或兩個。我想知道這是故意的還是UINavigationController中的錯誤。

我真正需要的是能夠看到什麼時候取消了互動流行音樂,可以在我的UINavigationController子類或UINavigationControllerDelegate中找到。有沒有一個明顯的方法來做到這一點?

編輯

我還在尋找一個解決方案,這一點,但想提一提,我已經報告這個問題,因爲與蘋果的錯誤。查看文檔,這些委託方法不應該被調用,特別是考慮到被調用的等效視圖生命週期方法。

EDIT2

我的雷達票(16823313)被關閉今日(2015年5月21日),並標記爲意。 :(

工程已確定以下信息基於 按預期這個問題表現:

這實際上是正確的行爲的導航過渡 多數民衆贊成的B發生的一切 - > A,如果取消這中間的過渡,你 不會得到didShowViewController:此方法過渡 的取消不應該被認爲從A過渡 - > B,因爲 你從來沒有真正達到A.

視圖[威爾/難道]應用耳朵仍然應該如預期那樣。

這是一個令人沮喪的情況,因爲它是違反直覺的,但我的答案中的解決方法應該在可預見的將來適用,至少在我的用例中是這樣。

+0

你有,我可以欺騙一個bug報告多少? –

+0

你好。我的錯誤報告編號是'16823313'。他們試圖在去年六月份的第一個iOS 8測試版中將其標記爲固定,並且在確認它仍然被破壞後我打開了它。從那以後沒有活動。 – Dima

回答

32

對於任何有興趣的人,我發現有兩種方法可以在UINavigationControllerDelegate級別解決此問題。

  1. 使用志願觀察interactivePopGestureRecognizerstate財產。不幸的是,取消轉換不會將狀態更改爲UIGestureRecognizerStateFailed,而只是UIGestureRecognizerStateEnded,因此如果需要識別已取消或已完成的流行音樂,您需要編寫一些附加代碼以跟蹤發生的情況。

  2. 經過測試後,這可能是更好的解決方案:使用navigationController:willShowViewController:animated:方法將通知塊添加到過渡協調器。它看起來是這樣的:

    - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated 
    { 
        [[self transitionCoordinator] notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> context) 
        { 
         if([context isCancelled]) 
         { 
          UIViewController *fromViewController = [context viewControllerForKey:UITransitionContextFromViewControllerKey]; 
          [self navigationController:navigationController willShowViewController:fromViewController animated:animated]; 
    
          if([self respondsToSelector:@selector(navigationController:didShowViewController:animated:)]) 
          { 
           NSTimeInterval animationCompletion = [context transitionDuration] * (double)[context percentComplete]; 
    
           dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((uint64_t)animationCompletion * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
            [self navigationController:navigationController didShowViewController:fromViewController animated:animated]; 
           }); 
          } 
    
    
         } 
        }]; 
    } 
    

我還在猶豫,在第一次使用該解決方案,因爲該文件是不清楚自己是否可以設置這些不止一個(因爲在這種情況下,如果不知道的視圖控制器也設置了自己的通知塊,它可能會取代這個通知塊或被這個通知塊取代)。經過測試後,它看起來並不是1:1的關係,您可以安全地添加多個通知塊。

編輯

我編輯上面的代碼延遲navigationController:didShowViewController:animated:呼叫時應該動畫完成,以更緊密地匹配預期違約行爲只能叫。

+0

偉大的解決方案!我面臨同樣的問題。但是viewControllers/topViewController呢?在調用這些方法的時刻,視圖控制器不會被添加到導航控制器堆棧中,因此topViewController將保留舊值。 – deej

+0

只要注意到它在手勢結束時觸發,但視圖控制器繼續移動 – deej

+0

也可以使用http://stackoverflow.com/questions/21298051 – deej

0

我翻譯@迪馬的answer斯威夫特爲我的項目:

func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) { 

    transitionCoordinator()?.notifyWhenInteractionEndsUsingBlock { context in 
     guard context.isCancelled(), let fromViewController = context.viewControllerForKey(UITransitionContextFromViewControllerKey) else { return } 

     self.navigationController(self, willShowViewController: fromViewController, animated: animated) 

     let animationCompletion: NSTimeInterval = context.transitionDuration() * Double(context.percentComplete()) 

     let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC))) 
     dispatch_after(delayTime, dispatch_get_main_queue()) { 
      self.navigationController(self, didShowViewController: fromViewController, animated: animated) 
     }    
    } 

    /* Your normal behavior goes here */ 

} 

請注意,我不檢查的navigationController(_:didShowViewController:animated:)實現的存在,但我相信這是在斯威夫特編譯時檢查,如果你試圖在未實現時調用它,你會得到一個編譯器錯誤。

+1

棒極了!我想補充一點,這個編譯時錯誤也會出現在Objective-C中。我在原始答案中加入這個檢查的原因是,您不必根據是否實施'... didShow ...'方法來修改此修補程序代碼。基本上,這是一個方便的補丁將工作,無論你有沒有。 – Dima

2

斯威夫特3:

func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { 
    transitionCoordinator?.notifyWhenInteractionEnds { context in 
     guard context.isCancelled, let fromViewController = context.viewController(forKey: UITransitionContextViewControllerKey.from) else { return } 
     self.navigationController(self, willShow: fromViewController, animated: animated) 
     let animationCompletion: TimeInterval = context.transitionDuration * Double(context.percentComplete) 
     DispatchQueue.main.asyncAfter(deadline: .now() + animationCompletion) { 
      self.navigationController(self, didShow: fromViewController, animated: animated) 
     } 
    } 
} 
+0

感謝您的支持! – Dima

相關問題