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