Жест слайда с пользовательской кнопкой "назад" замораживает корневой контроллер вида

У меня есть пользовательские кнопки возврата по всему моему приложению, и, похоже, навигационному контроллеру это не нравится.

Итак, я хочу, чтобы жест 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

Objective-C

У меня та же проблема, вот мое решение: в вашем пользовательском NavigationController, как MYNavigationController, так как вы устанавливаете делегат жестов на navigationController, вы можете добавить туда метод делегата:

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
    if (self.viewControllers.count>1) {
        return YES;
    }
    return NO;
}
тогда он остановит всплывающее действие, когда он находится в корневом viewController и избегает зависания.

Вот мой ответ на аналогичный вопрос, заданный здесь

Вы можете использовать небольшую хитрость, чтобы заставить работать родной жест. Создать подкласс 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)" +
                   "------")
    }
}
Другие вопросы по тегам