Жест слайда с пользовательской кнопкой "назад" замораживает корневой контроллер вида
У меня есть пользовательские кнопки возврата по всему моему приложению, и, похоже, навигационному контроллеру это не нравится.
Итак, я хочу, чтобы жест iOS7 смахивания назад возвращался к моим настраиваемым кнопкам возврата. Искал и пробовал разные способы, но ни один не кажется многообещающим. Самое близкое, что я мог получить, это с http://keighl.com/post/ios7-interactive-pop-gesture-custom-back-button/. Однако теперь, когда я продолжаю толкать и выдвигать стек навигации, через некоторое время rootViewController в стеке перестает отвечать на любые прикосновения.
Какие-либо предложения?
5 ответов
Подкласс UINavigationController, как предлагает Кейгл, является правильным подходом imo. Но он пропускает проверку контроллера корневого представления, чтобы избежать зависания при выполнении жеста в корневом представлении. Вот модифицированная версия с дополнительной проверкой:
CBNavigationController.h:
#import <UIKit/UIKit.h>
@interface CBNavigationController : UINavigationController <UIGestureRecognizerDelegate, UINavigationControllerDelegate>
@end
CBNavigationController.m:
#import "CBNavigationController.h"
@interface CBNavigationController ()
@end
@implementation CBNavigationController
- (void)viewDidLoad
{
NSLog(@"%s",__FUNCTION__);
__weak CBNavigationController *weakSelf = self;
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
{
self.interactivePopGestureRecognizer.delegate = weakSelf;
self.delegate = weakSelf;
}
}
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
NSLog(@"%s",__FUNCTION__);
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
self.interactivePopGestureRecognizer.enabled = NO;
[super pushViewController:viewController animated:animated];
}
#pragma mark UINavigationControllerDelegate
- (void)navigationController:(UINavigationController *)navigationController
didShowViewController:(UIViewController *)viewController
animated:(BOOL)animate
{
NSLog(@"%s",__FUNCTION__);
// Enable the gesture again once the new controller is shown AND is not the root view controller
if (viewController == self.viewControllers.firstObject)
{
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
self.interactivePopGestureRecognizer.enabled = NO;
}
else
{
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
self.interactivePopGestureRecognizer.enabled = YES;
}
}
@end
У меня та же проблема, вот мое решение: в вашем пользовательском NavigationController, как MYNavigationController
, так как вы устанавливаете делегат жестов на navigationController, вы можете добавить туда метод делегата:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
if (self.viewControllers.count>1) {
return YES;
}
return NO;
}
Вот мой ответ на аналогичный вопрос, заданный здесь
Вы можете использовать небольшую хитрость, чтобы заставить работать родной жест. Создать подкласс UINavigationItem
затем переопределить leftBarButtonItems
метод:
- (NSArray*)leftBarButtonItems
{
return nil;
}
Теперь используйте этот класс для элемента, который имеет пользовательский левый UIBarButtonItem
, Жест работает! Это потому что UINavigationController
думает, что нет оставленных предметов и включает жест. Вы по-прежнему можете получить доступ к своему элементу через leftBarButtonItem
имущество.
Даже у меня была та же проблема, я исправил ее, изменив код, указанный в ссылке, на которую вы ссылаетесь. Теперь мои экраны зависают очень редко, все еще находя для постоянного исправления.
@implementation PPNavigationController
-(void)viewDidLoad
{
//[super viewDidLoad];
// Do any additional setup after loading the view.
__weak PPNavigationController *weakSelf = self;
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
{
self.interactivePopGestureRecognizer.delegate = weakSelf;
self.delegate = weakSelf;
}
}
-(void)navigationController:(UINavigationController *)navigationController
didShowViewController:(UIViewController *)viewController
animated:(BOOL)animate
{
// Enable the gesture again once the new controller is shown
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
self.interactivePopGestureRecognizer.delegate = viewController;
}
Don't use this method
//-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
//}
Вот простой подкласс Swift UINavigationController
Вы можете использовать то, что я адаптировал из ответа @ слабого. Не должно быть необходимости осуществлять UIGestureRecognizerDelegate
как военно-морской делегат navigationController(_:didShow:animated:)
обрабатывает работу по включению и отключению поп-жеста.
Использование этого подкласса в раскадровке или коде проще, чем одноразовое отключение в других контроллерах, встроенных в контроллеры nav.
import UIKit
@objc class LWNavigationController : UINavigationController,
UINavigationControllerDelegate {
override func viewDidLoad() {
self.delegate = self
}
override func pushViewController(_ viewController: UIViewController,
animated: Bool) {
// Disable this gesture while animating a push.
self.interactivePopGestureRecognizer?.isEnabled = false
super.pushViewController(viewController, animated: animated)
debugPrint("------\(#function) \(viewController)------")
}
// MARK: - UINavigationControllerDelegate
func navigationController(_ navigationController: UINavigationController,
didShow viewController: UIViewController,
animated: Bool) {
if (viewController == self.viewControllers.first) {
// Keep the gesture disabled if we're at the root to avoid back swipes
// from corrupting the navigation stack.
self.interactivePopGestureRecognizer?.isEnabled = false
} else {
self.interactivePopGestureRecognizer?.isEnabled = true
}
debugPrint("------\(#function) \(viewController) " +
"enabled: \(self.interactivePopGestureRecognizer?.isEnabled)" +
"------")
}
}