IOS 7 использует пользовательские интерактивные переходы только некоторое время

Итак, у меня есть UINavigationController, с контроллером A в качестве корневого контроллера.

Когда я хочу нажать Controller B сверху, я хочу использовать настраиваемый анимированный переход и пользовательский интерактивный переход. Это прекрасно работает.

Когда я хочу нажать Controller C сверху, я хочу вернуться к переходу push/pop по умолчанию, который поставляется с UINavigationController. Чтобы это произошло, я возвращаю nil для

navigationController:animationControllerForOperation:fromViewController:toViewController:

однако, если вы вернете nil, тогда

navigationController:interactionControllerForAnimationController:

никогда не будет вызываться, а по умолчанию "полет с левого края" не работает.

Есть ли способ вернуть стандартный контроллер push/pop анимации и контроллер взаимодействия? (Существуют ли конкретные реализации id<UIViewControllerAnimatedTransitioning> и id<UIViewControllerInteractiveTransitioning>?)

Или каким-то другим способом?

Ответы

Ответ 1

Вы должны установить делегат interactiveCopGestureRecognizer NavigationController для себя, а затем обработать его поведение в -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;
}

Вы можете проверить образец проекта для своего сценария. Переходы между контроллерами вида A и B настраиваются анимированными, с обычным жестком B- > A pop. Переходы между контроллерами представлений B и C по умолчанию, со встроенным жестким поведением навигационного контроллера.

Надеюсь, это поможет!

Ответ 2

Вам нужно будет установить делегат каждый раз, пока вы не представите - например, в prepareForSeque. Если вам нужен пользовательский переход, установите его в self. Если вы хотите, чтобы переход по умолчанию (например, поп-по умолчанию) установил его равным нулю.

Ответ 3

Настройка делегата до/после каждого перехода является допустимым обходным путем, но если вы реализуете другие методы UINavigationControllerDelegate, и вам нужно их сохранить, вы можете либо иметь 2 объекта-делегата, как предлагается Ziconic, либо играть с 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 по мере необходимости. В вашем примере вы должны установить свойство YES только тогда, когда отображается контроллер A.

Есть еще одна вещь: принудительно UINavigationController переоценивает методы, реализованные его делегатом. Это можно легко сделать, выполнив что-то вроде этого:

navigationController.delegate = nil;
navigationController.delegate = self; // or whatever object you use as the delegate

Ответ 4

попробуйте установить (self.)navigationController.delegate в nil (или вернуть его к предыдущему значению) после того, как вы выполнили свой собственный переход.

Ответ 5

в вашем распознавателе жестов, установите делегат (для себя) и верните свои анимированные и интерактивные переходы. при возврате интерактивного перехода обязательно отмените делегирование, чтобы все остальное продолжало использовать переходы по умолчанию.

У меня есть рабочий рабочий пример github.

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