2013-11-21 3 views
13

私はUINavigationControllerを持っています。コントローラーAをルートコントローラーとして使用しています。iOS 7では、カスタムのインタラクティブなトランジションを使用することがあります。

コントローラーBを上に押したいときは、アニメーションのカスタムトランジションとカスタムのインタラクティブなトランジションを使用したいと思います。これは正常に動作します。私が上にコントローラーCをプッシュするとき

は、私はUINavigationControllerが付属していますデフォルトプッシュ/ポップ遷移にフォールバックします。これは私があなたがnilを返した場合、その後、

navigationController:interactionControllerForAnimationController: 

が呼び出されることはありませんし、デフォルトの「左端からパンは」インタラクティブ移行が動作しませんポップ。しかし

navigationController:animationControllerForOperation:fromViewController:toViewController: 

にnilを返す実現するために

デフォルトのプッシュ/ポップアニメーションコントローラとインタラクションコントローラを返す方法はありますか? (id<UIViewControllerAnimatedTransitioning>id<UIViewControllerInteractiveTransitioning>の具体的な実装はありますか?)

または他の方法ですか?

答えて

18

あなたは自分にNavigationControllerのinteractivePopGestureRecognizerデリゲートを設定し、-gestureRecognizerShouldBeginにその動作を処理する必要があります

あなたは内蔵のポップジェスチャー火災にしたいとき、あなたはこのメソッドからYES返す必要があり、です。あなたのカスタムジェスチャーにも同じことが言えます。あなたがどのレコグナイザを扱っているのか把握しなければなりません。

- (void)setup 
{ 
    self.interactiveGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleTransitionGesture:)]; 
    self.interactiveGestureRecognizer.delegate = self; 
    [self.navigationController.view addGestureRecognizer:self.interactiveGestureRecognizer]; 

    self.navigationController.interactivePopGestureRecognizer.delegate = self; 
} 

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer 
{ 
    // Don't handle gestures if navigation controller is still animating a transition 
    if ([self.navigationController.transitionCoordinator isAnimated]) 
     return NO; 

    if (self.navigationController.viewControllers.count < 2) 
     return NO; 

    UIViewController *fromVC = self.navigationController.viewControllers[self.navigationController.viewControllers.count-1]; 
    UIViewController *toVC = self.navigationController.viewControllers[self.navigationController.viewControllers.count-2]; 

    if ([fromVC isKindOfClass:[ViewControllerB class]] && [toVC isKindOfClass:[ViewControllerA class]]) 
    { 
     if (gestureRecognizer == self.interactiveGestureRecognizer) 
      return YES; 
    } 
    else if (gestureRecognizer == self.navigationController.interactivePopGestureRecognizer) 
    { 
     return YES; 
    } 

    return NO; 
} 

あなたのシナリオでは、sample projectをチェックアウトすることができます。ビューコントローラAとBとの間の遷移は、カスタムB→Aポップジェスチャでカスタムアニメーションされます。ビューコントローラBとCとの間の遷移はデフォルトであり、ナビゲーションコントローラのポップジェスチャが組み込まれています。

希望すると便利です。

+0

アップルのDTSの人々によると、民間interactivePopGestureRecognizer UINavigationControllerに付属のプライベートAPIを呼び出し、その一部デリゲートでチェックし、数がないこと。あなた自身のデリゲートを実装することは、すべてのケースの100%をカバーする保証はありません。 – Ziconic

+0

@Ziconicの例の場合? – Andy

0

カスタムトランジションを実行した後に(self.)navigationController.delegatenilに設定してください(以前の値に戻してください)。

10

プレゼンテーションを行う前に、いつでもデリゲートを設定する必要があります:例えば、prepareForSeque:カスタムトランジションを希望する場合は、それをselfに設定します。デフォルトのトランジション(デフォルトのポップトランジションのような)を望むなら、それをnilに設定します。

+1

悲しいことに、これは実際には正解ではなくても、アップルのDTSスタッフがお勧めするアプローチです。基本的には、2つのUINavigationControllerDelegateオブジェクトが必要です.1つは遷移コールバックを実装し、もう1つは(またはゼロではありません)オブジェクトです。デフォルトのポップトランジションを取得するには、コールバックなしでデリゲートを使用します(またはデリゲートをnilに設定します)。カスタムトランジションを取得するには、コールバックを持つデリゲートをスワップアウトします(トランジション完了後に元のデリゲートを復元します)。 – Ziconic

+0

これは引き続き推奨されるアプローチですか? – ken

+0

@kenそれはiOS 7&8で動作するので、私ははいと言うでしょう。 – Jesse

0

ジェスチャーレコグナイザーで、(自分自身に)デリゲートを設定し、アニメーションとインタラクティブなトランジションを返します。インタラクティブなトランジションを返すときは、のデリゲートをもう一度解除して、他のすべてのトランジションが引き続きデフォルトのトランジションを使用するようにしてください。

私にはworking example on githubがあります。

各遷移が有効な回避策ですが、あなたは他の UINavigationControllerDelegateのメソッドを実装し、それらを維持する必要がある場合は、あなたが示唆したようにZiconicで2つのデリゲートオブジェクトを持っているかで遊ぶことができますいずれかの後/前に、デリゲートを設定
- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController 
{ 
    // Unset the delegate so that all other types of transitions (back, normal animated push not initiated by a gesture) get the default behavior. 
    self.navigationController.delegate = nil; 

    if (self.edgePanGestureRecognizer.state == UIGestureRecognizerStateBegan) { 
    self.percentDrivenInteractiveTransition = [UIPercentDrivenInteractiveTransition new]; 
    } else { 
    self.percentDrivenInteractiveTransition = nil; 
    } 

    return self.percentDrivenInteractiveTransition; 
} 
1

NSObjectのrespondsToSelector:。あなたのナビゲーションデリゲートでは、実現することができます。

- (BOOL)respondsToSelector:(SEL)aSelector 
{ 
    if (aSelector == @selector(navigationController:animationControllerForOperation:fromViewController:toViewController:) || 
     aSelector == @selector(navigationController:interactionControllerForAnimationController:)) { 

     return self.interactivePushTransitionEnabled; 
    } 

    return [super respondsToSelector:aSelector]; 
} 

あなたは、その後、必要に応じてinteractivePushTransitionEnabledを更新するようにしてください。あなたの例では、コントローラAが表示されている場合にのみ、プロパティをYESに設定する必要があります。

もう1つのことがあります。強制的にUINavigationControllerがデリゲートによって実装されたメソッドを再評価します。これは簡単にこのような何かを行うことによって行うことができます。

navigationController.delegate = nil; 
navigationController.delegate = self; // or whatever object you use as the delegate 
関連する問題