Как отключить жест смахивания назад в UINavigationController на iOS 7

296

В iOS 7 Apple добавила новое поведение навигации по умолчанию. Вы можете прокручивать левый край экрана, чтобы вернуться в стек навигации. Но в моем приложении это поведение конфликтует с моим пользовательским меню слева. Итак, можно ли отключить этот новый жест в UINavigationController?

Теги:
uinavigationcontroller
uigesturerecognizer
ios7

15 ответов

551
Лучший ответ

Я нашел решение:

Objective-C:

if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
    self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}

Swift 3:
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false

  • 0
    Это вызывает недопустимый аргумент исключение при запуске на iOS6.
  • 26
    Конечно, вам нужно проверить наличие новых методов, если вы поддерживаете старые версии iOS.
Показать ещё 14 комментариев
42

Я выяснил, что установка жестов для инвалидов только не всегда работает. Он работает, но для меня это произошло только после того, как я когда-то использовал заставку. Второй раз это не вызовет зарождение.

Исправить для меня было делегировать жест и реализовать метод shouldbegin для возврата NO:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    // Disable iOS 7 back gesture
    if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.navigationController.interactivePopGestureRecognizer.enabled = NO;
        self.navigationController.interactivePopGestureRecognizer.delegate = self;
    }
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    // Enable iOS 7 back gesture
    if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.navigationController.interactivePopGestureRecognizer.enabled = YES;
        self.navigationController.interactivePopGestureRecognizer.delegate = nil;
    }
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    return NO;
}
  • 1
    Спасибо! Это необходимо для полного отключения обратного пролистывания. Это все еще существует в iOS 8, и пахнет как ошибка Apple.
  • 0
    Спасибо, похоже, единственное, что сработало.
Показать ещё 6 комментариев
25

Просто удалите распознаватель жестов из NavigationController. Работа в iOS 8.

if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])
    [self.navigationController.view removeGestureRecognizer:self.navigationController.interactivePopGestureRecognizer];
  • 0
    единственное решение, которое на самом деле работает в IOS 8 и 9
  • 6
    Также работает в iOS 10, это должен быть принятый ответ. Кстати, если вы хотите повторно включить его, сделайте [self.navigationController.view addGestureRecognizer:self.navigationController.interactivePopGestureRecognizer] где-нибудь.
20

Как и в iOS 8, принятый ответ больше не работает. Мне нужно было остановить разворот, чтобы убрать жест на моем главном экране игры, чтобы это реализовано:

- (void)viewDidAppear:(BOOL)animated
{
     [super viewDidAppear:animated];

if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
    self.navigationController.interactivePopGestureRecognizer.delegate = self;
    }
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
    self.navigationController.interactivePopGestureRecognizer.delegate = nil;
    }

}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
     return NO;
}
  • 2
    Хотя это работает с iOS8, я получаю предупреждение в строке * .delegate = self; заявляя: присвоение идентификатору <UIGestureRecognizerDelegate> 'из несовместимого типа' ViewController * const __strong '
  • 2
    Начиная с iOS8, принятый ответ по-прежнему работает, как и ожидалось. Вы, вероятно, делаете что-то еще не так ..
Показать ещё 5 комментариев
17

Я немного уточнил Twan, потому что:

  • ваш контроллер просмотра может быть установлен в качестве делегата для других распознавателей жестов.
  • настройка делегата на nil приводит к зависанию при возврате к контроллеру корневого представления и делает жест жесткой передачи перед перемещением в другом месте.

В следующем примере предполагается iOS 7:

{
    id savedGestureRecognizerDelegate;
}

- (void)viewWillAppear:(BOOL)animated
{
    savedGestureRecognizerDelegate = self.navigationController.interactivePopGestureRecognizer.delegate;
    self.navigationController.interactivePopGestureRecognizer.delegate = self;
}

- (void)viewWillDisappear:(BOOL)animated
{
    self.navigationController.interactivePopGestureRecognizer.delegate = savedGestureRecognizerDelegate;
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer == self.navigationController.interactivePopGestureRecognizer) {
        return NO;
    }
    // add whatever logic you would otherwise have
    return YES;
}
7

Пожалуйста, установите это в корневом каталоге vc:

-(void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:YES];
    self.navigationController.interactivePopGestureRecognizer.enabled = NO;

}

-(void)viewDidDisappear:(BOOL)animated{
    [super viewDidDisappear:YES];
    self.navigationController.interactivePopGestureRecognizer.enabled = YES;
}
7

ИЗМЕНИТЬ

Если вы хотите управлять функцией прокрутки назад для определенных навигационных контроллеров, рассмотрите возможность использования SwipeBack.

С помощью этого вы можете установить navigationController.swipeBackEnabled = NO.

Например:

#import <SwipeBack/SwipeBack.h>

- (void)viewWillAppear:(BOOL)animated
{
    navigationController.swipeBackEnabled = NO;
}

Он может быть установлен через CocoaPods.

pod 'SwipeBack', '~> 1.0'

Я извиняюсь из-за отсутствия объяснений.

  • 4
    При продвижении проекта, с которым вы связаны, вы должны раскрыть свою принадлежность к нему.
  • 1
    Кроме того, единственная цель вашего проекта - вручную включить жест смахивания, когда системный по умолчанию не работает, тогда как вопрос состоит в том, как отключить этот общесистемный жест, так что даже если вы установите self.navigationController.swipeBackEnabled = NO I'm Я уверен, что это только отключит жест назад вашей библиотеки, но системный будет по-прежнему включен.
Показать ещё 6 комментариев
5

он работает для меня в ios 10 и более поздних версиях:

- (void)viewWillAppear:(BOOL)animated {
    if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.navigationController.interactivePopGestureRecognizer.enabled = NO;
    }

}

он не работает с методом viewDidLoad().

4

Для Swift:

navigationController!.interactivePopGestureRecognizer!.enabled = false
  • 7
    Это работает, хотя я бы предложил использовать необязательную цепочку вместо принудительного развертывания. например, self.navigationController? .interactivePopGestureRecognizer? .isEnabled = false
2

Это путь на Swift 3

работает для меня

    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
2

Мой метод. Один распознаватель жестов, чтобы управлять всеми ними:

class DisabledGestureViewController: UIViewController: UIGestureRecognizerDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        navigationController!.interactivePopGestureRecognizer!.delegate = self
    }

    func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
        // Prevent going back to the previous view
        return !(navigationController!.topViewController is DisabledGestureViewController)
    }
}

Важно: не reset делегат в любом месте стека навигации: navigationController!.interactivePopGestureRecognizer!.delegate = nil

2

Все эти решения управляют распознающим жестом Apple способом, который они не рекомендуют. Мне только что сказал друг, что есть лучшее решение:

[navigationController.interactivePopGestureRecognizer requireGestureRecognizerToFail: myPanGestureRecognizer];

где myPanGestureRecognizer - распознаватель жестов, который вы используете, например, покажите свое меню. Таким образом, распознаватель жестов Apple не возвращается к ним, когда вы нажимаете новый контроллер навигации, и вам не нужно полагаться на сдержанные задержки, которые могут срабатывать слишком рано, если ваш телефон укладывается спать или находится под большой нагрузкой.

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

  • 0
    Это должен быть принятый ответ!
2

Ни один из этих ответов не помог мне решить проблему. Проводя свой ответ здесь; может быть полезно для кого-то

Объявить private var popGesture: UIGestureRecognizer? как глобальную переменную в вашем диспетчере просмотра. Затем выполните код в viewDidAppear и viewWillDisappear методы

override func viewDidAppear(animated: Bool) {

    super.viewDidAppear(animated)

    if self.navigationController!.respondsToSelector(Selector("interactivePopGestureRecognizer")) {

        self.popGesture = navigationController!.interactivePopGestureRecognizer
        self.navigationController!.view.removeGestureRecognizer(navigationController!.interactivePopGestureRecognizer!)
    }
}


override func viewWillDisappear(animated: Bool) {

    super.viewWillDisappear(animated)

    if self.popGesture != nil {
        navigationController!.view.addGestureRecognizer(self.popGesture!)
    }
}

Это отключит прокрутку обратно в iOS v8.x вперед

  • 0
    Я пытаюсь представить, при каких обстоятельствах это будет работать, но Джек не будет. Вы говорите, что пробовали все остальные ответы: что пошло не так, когда вы попробовали Джек?
  • 0
    С другой стороны, это кажется проще, чем у Джека, так что, возможно, это не важно. Решил, что мне это нравится, потому что не нужно объявлять мой класс делегатом или манипулировать interactivePopGestureRecognizer.delegate .
Показать ещё 1 комментарий
2

Это работает в viewDidLoad: для iOS 8:

  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
      self.navigationController.interactivePopGestureRecognizer.enabled = false;
  });

Множество проблем можно было решить с помощью хорошего ol dispatch_after.

Обратите внимание, что это решение потенциально небезопасно, пожалуйста, используйте свои собственные аргументы.

Обновление

Для iOS 8.1 время задержки должно составлять 0,5 секунды

В iOS 9.3 больше не требуется отсрочка, она работает просто, помещая это в свой viewDidLoad:
(TBD, если работает на iOS 9.0-9.3)

navigationController?.interactivePopGestureRecognizer?.enabled = false
  • 0
    Если вы не знаете, когда в представлении установлен распознаватель жестов, ожидание произвольного количества времени для его отключения может работать, а может и не работать.
  • 0
    @kalperin это не гарантированно работает, хотя иногда это очень удобное решение. Используйте свои собственные рассуждения.
Показать ещё 5 комментариев
1

Для Swift 4 это работает:

class MyViewController: UIViewController, UIGestureRecognizerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        self.navigationController?.interactivePopGestureRecognizer?.gesture.delegate = self
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)

        self.navigationController?.interactivePopGestureRecognizer?.gesture.isEnabled = false
    }

}
  • 0
    Не следует переопределять делегат интерактивного жеста, поскольку это приведет к недокументированному поведению.
  • 0
    Я думаю, что это не переопределение делегата, а просто изменение логической переменной, которую они предоставили для этой цели, так что это не будет проблемой.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню