Pas de balayage arrière lors du masquage de la barre de navigation dans UINavigationController

86

J'adore le pack swipe hérité de l'intégration de vos vues dans un fichier UINavigationController. Malheureusement, je n'arrive pas à trouver un moyen de masquer le NavigationBarmais j'ai toujours le balayage tactile en arrière gesture. Je peux écrire des gestes personnalisés mais je préfère ne pas le faire et me fier plutôt au UINavigationControllerbalayage arrière gesture.

si je le décoche dans le storyboard, le balayage arrière ne fonctionne pas

entrez la description de l'image ici

sinon, si je le cache par programme, le même scénario.

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.navigationController setNavigationBarHidden:YES animated:NO]; // and animated:YES
}

N'y a-t-il aucun moyen de masquer le haut NavigationBaret de toujours avoir le balayage?

Mihai
la source
1
L'ajout d'un UIGestureRecognizer est-il acceptable? C'est un jeu d'enfant à mettre en œuvre.
SwiftArchitect
1
@LancelotdelaMare, j'essayais d'éviter cela car cela ne fonctionnera pas aussi bien que le balayage arrière UINavigationController. Im regardant dans UIScreenEdgePanGestureRecognizer car certaines personnes disent que cela aide mais ne l'ont pas encore fait fonctionner. Vous recherchez la solution la plus simple et la plus élégante ici.
mihai

Réponses:

96

Un hack qui fonctionne est de régler le interactivePopGestureRecognizerdélégué » du UINavigationControllerà la nilmanière suivante:

[self.navigationController.interactivePopGestureRecognizer setDelegate:nil];

Mais dans certaines situations, cela pourrait créer des effets étranges.

ChevalT
la source
16
"balayer en arrière à plusieurs reprises peut provoquer la reconnaissance du geste lorsqu'il n'y a qu'un seul contrôleur de vue sur la pile, ce qui à son tour met une interface utilisateur dans un état (je pense inattendu par les ingénieurs UIKit) où elle cesse de reconnaître les gestes"
HorseT
4
Une alternative qui pourrait protéger contre cet état inattendu serait de le définir sur un objet de bas niveau (j'ai utilisé mon délégué d'application) et de l'implémenter gestureRecognizerShouldBegin, en retournant truesi le nombre navigationControllerde s viewControllerest supérieur à 0.
Kenny Winker
4
Bien que cela fonctionne, je recommande vivement de ne pas cela. La rupture du délégué provoquait un bloc de thread principal rare et difficile à identifier. Il s'avère que ce n'est pas un bloc de thread principal mais c'est ce que @HorseT a décrit.
Josh Bernfeld
3
Mon application enregistre la poignée du délégué, puis la restaure viewWillDisappearet jusqu'à présent, je n'ai pas eu d'effets secondaires indésirables.
Don Park
1
!!!! Découragez fortement d'utiliser cette solution, lorsque vous utilisez à plusieurs reprises un balayage, un comportement étrange se produit, le dos est désactivé et toute l'application ne répond plus
KarimIhab
79

Problèmes avec d'autres méthodes

Le réglage interactivePopGestureRecognizer.delegate = nila des effets secondaires inattendus.

Le paramètre navigationController?.navigationBar.hidden = truefonctionne, mais ne permet pas de masquer votre modification dans la barre de navigation.

Enfin, il est généralement préférable de créer un objet modèle correspondant UIGestureRecognizerDelegateà votre contrôleur de navigation. Le paramétrer sur un contrôleur de la UINavigationControllerpile est à l'origine des EXC_BAD_ACCESSerreurs.

Solution complète

Tout d'abord, ajoutez cette classe à votre projet:

class InteractivePopRecognizer: NSObject, UIGestureRecognizerDelegate {

    var navigationController: UINavigationController

    init(controller: UINavigationController) {
        self.navigationController = controller
    }

    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return navigationController.viewControllers.count > 1
    }

    // This is necessary because without it, subviews of your top controller can
    // cancel out your gesture recognizer on the edge.
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
}

Ensuite, définissez votre contrôleur de navigation interactivePopGestureRecognizer.delegatesur une instance de votre nouvelle InteractivePopRecognizerclasse.

var popRecognizer: InteractivePopRecognizer?

override func viewDidLoad() {
    super.viewDidLoad()
    setInteractiveRecognizer()
}

private func setInteractiveRecognizer() {
    guard let controller = navigationController else { return }
    popRecognizer = InteractivePopRecognizer(controller: controller)
    controller.interactivePopGestureRecognizer?.delegate = popRecognizer
}

Profitez d'une barre de navigation cachée sans effets secondaires, qui fonctionne même si votre contrôleur supérieur possède des sous-vues de table, de collection ou de défilement.

Moine chasseur
la source
1
Excellente solution!
Matt Butler
1
La meilleure réponse, merci!
Dory Daniel
2
@HunterMaximillionMonk merci pour cette excellente solution. Cela fonctionne comme un charme
comme diu
1
@HunterMaximillionMonk cela semble fonctionner correctement, mais le problème avec cela lorsque j'ai plusieurs contrôleurs, puis après une fois, il cesse de fonctionner.
Premal Khetani
1
Certainement la meilleure réponse!
daxh
54

Dans mon cas, pour éviter les effets étranges

Contrôleur de vue racine

override func viewDidLoad() {
    super.viewDidLoad()

    // Enable swipe back when no navigation bar
    navigationController?.interactivePopGestureRecognizer?.delegate = self 

}


func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    if(navigationController!.viewControllers.count > 1){
        return true
    }
    return false
}

http://www.gampood.com/pop-viewcontroller-with-out-navigation-bar/

Saranpol
la source
2
Parfois, j'obtiens EXC_BAD_ACCESS lorsque j'utilise ceci
Andrey Gordeev
Pour moi, cela ne fait pas fonctionner le geste et se bloque fréquemment avec leEXEC_BAD_ACCESS
Benjohn
2
N'oubliez pas d'ajouter UIGestureRecognizerDelegateau contrôleur de vue racine ... Dans mon cas, le délégué a été défini sur nil dans un contrôleur de vue plus récent que le contrôleur de vue racine, donc lorsqu'il est retourné au contrôleur de vue racine, il gestureRecognizerShouldBeginn'a pas été appelé. Alors j'ai placé le .delegate = selfdedans viewDidAppear(). Cela a résolu les effets étranges dans mon cas .. Cheers!
Wiingaard
@AndreyGordeev Pourriez-vous s'il vous plaît donner quelques détails sur quand EXEC_BAD_ACCESScela se produit?
Jaybo
Voici plus d'informations sur l' EXC_BAD_ACCESSerreur: stackoverflow.com/questions/28746123/…
Andrey Gordeev
25

Mis à jour pour iOS 13.4

iOS 13.4 a cassé la solution précédente, donc les choses vont devenir moche. Il semble que dans iOS 13.4, ce comportement est désormais contrôlé par une méthode privée _gestureRecognizer:shouldReceiveEvent:(à ne pas confondre avec la nouvelle shouldReceiveméthode publique ajoutée dans iOS 13.4).


J'ai trouvé que d'autres solutions publiées remplaçant le délégué ou le définissant sur nul provoquaient un comportement inattendu.

Dans mon cas, lorsque j'étais au sommet de la pile de navigation et que j'essayais d'utiliser le geste pour en faire apparaître un de plus, cela échouait (comme prévu), mais les tentatives ultérieures de pousser sur la pile commenceraient à provoquer d'étranges problèmes graphiques dans le barre de navigation. Cela a du sens, car le délégué est utilisé pour gérer plus que simplement s'il faut ou non empêcher le geste d'être reconnu lorsque la barre de navigation est masquée et que tous ces autres comportements ont été rejetés.

D'après mes tests, il semble que ce gestureRecognizer(_:, shouldReceiveTouch:)soit la méthode que le délégué d'origine met en œuvre pour empêcher le geste d'être reconnu lorsque la barre de navigation est masquée, non gestureRecognizerShouldBegin(_:). D'autres solutions qui implémentent gestureRecognizerShouldBegin(_:)dans leur travail de délégué parce que l'absence d'une implémentation de gestureRecognizer(_:, shouldReceiveTouch:)provoquera le comportement par défaut de recevoir toutes les touches.

La solution de @Nathan Perry se rapproche, mais sans implémentation de respondsToSelector(_:), le code UIKit qui envoie des messages au délégué croira qu'il n'y a pas d'implémentation pour aucune des autres méthodes de délégué, et forwardingTargetForSelector(_:)ne sera jamais appelé.

Donc, nous prenons le contrôle de `gestureRecognizer (_ :, shouldReceiveTouch :) dans le scénario spécifique, nous voulons modifier le comportement, et sinon transmettre tout le reste au délégué.

class AlwaysPoppableNavigationController : UINavigationController {

    private var alwaysPoppableDelegate: AlwaysPoppableDelegate!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.alwaysPoppableDelegate = AlwaysPoppableDelegate(navigationController: self, originalDelegate: self.interactivePopGestureRecognizer!.delegate!)
        self.interactivePopGestureRecognizer!.delegate = self.alwaysPoppableDelegate
    }
}

private class AlwaysPoppableDelegate : NSObject, UIGestureRecognizerDelegate {

    weak var navigationController: AlwaysPoppableNavigationController?
    weak var originalDelegate: UIGestureRecognizerDelegate?

    init(navigationController: AlwaysPoppableNavigationController, originalDelegate: UIGestureRecognizerDelegate) {
        self.navigationController = navigationController
        self.originalDelegate = originalDelegate
    }

    // For handling iOS before 13.4
    @objc func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        if let navigationController = navigationController, navigationController.isNavigationBarHidden && navigationController.viewControllers.count > 1 {
            return true
        }
        else if let originalDelegate = originalDelegate {
            return originalDelegate.gestureRecognizer!(gestureRecognizer, shouldReceive: touch)
        }
        else {
            return false
        }
    }

    // For handling iOS 13.4+
    @objc func _gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceiveEvent event: UIEvent) -> Bool {
        if let navigationController = navigationController, navigationController.isNavigationBarHidden && navigationController.viewControllers.count > 1 {
            return true
        }
        else if let originalDelegate = originalDelegate {
            let selector = #selector(_gestureRecognizer(_:shouldReceiveEvent:))
            if originalDelegate.responds(to: selector) {
                let result = originalDelegate.perform(selector, with: gestureRecognizer, with: event)
                return result != nil
            }
        }

        return false
    }

    override func responds(to aSelector: Selector) -> Bool {
        if #available(iOS 13.4, *) {
            // iOS 13.4+ does not need to override responds(to:) behavior, it only uses forwardingTarget
            return originalDelegate?.responds(to: aSelector) ?? false
        }
        else {
            if aSelector == #selector(gestureRecognizer(_:shouldReceive:)) {
                return true
            }
            else {
                return originalDelegate?.responds(to: aSelector) ?? false
            }
        }
    }

    override func forwardingTarget(for aSelector: Selector) -> Any? {
        if #available(iOS 13.4, *), aSelector == #selector(_gestureRecognizer(_:shouldReceiveEvent:)) {
            return nil
        }
        else {
            return self.originalDelegate
        }
    }
}
Chris Vasselli
la source
1
Il semble que votre solution soit la meilleure pour le moment. Merci!
Timur Bernikovich
"mais les tentatives ultérieures de pousser sur la pile commenceraient à provoquer d'étranges problèmes graphiques dans la barre de navigation" - Je suis confus ici. Je pensais que nous n'avions pas de barre de navigation? C'est ça la question? Dans ma situation, j'ai un contrôleur de navigation intégré en tant que contrôleur de vue enfant sans barre de navigation; le conteneur VC a les commandes de navigation. J'ai donc laissé le conteneur VC être le délégué du programme de reconnaissance et j'ai juste fait la gestureRecognizerShouldBegin:chose, et cela "semble fonctionner". Je me demande si je devrais faire attention.
skagedal
2
Il y avait une fuite de mémoire car navigationControllerc'était une référence forte dans AlwaysPoppableDelegate. J'ai modifié le code pour en faire une weakréférence.
Graham Perks
3
Cette belle solution ne fonctionne plus sous iOS 13.4
Ely
@ChrisVasselli Vraiment génial, merci! Espérons que cela passera la vérification des méthodes privées de l'examen de l'App Store.
Ely le
16

Vous pouvez sous-classer UINavigationController comme suit:

@interface CustomNavigationController : UINavigationController<UIGestureRecognizerDelegate>

@end

La mise en oeuvre:

@implementation CustomNavigationController

- (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated {
    [super setNavigationBarHidden:hidden animated:animated];
    self.interactivePopGestureRecognizer.delegate = self;
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    if (self.viewControllers.count > 1) {
        return YES;
    }
    return NO;
}

@end
Yogesh Maheshwari
la source
2
Utiliser cette approche, c'est casser le geste pop en UIPageViewControllersurvol.
atulkhatri
J'ai trouvé que viewController.count> 1 check est nécessaire. Si l'utilisateur tente de revenir en arrière avec uniquement le VC racine, l'interface utilisateur se bloque lors de la prochaine poussée du VC.
VaporwareWolf
11

Réponse simple, sans effet secondaire

Bien que la plupart des réponses ici soient bonnes, elles ont apparemment des effets secondaires involontaires (rupture d'application) ou sont verbeuses.

La solution la plus simple mais la plus fonctionnelle que j'ai pu trouver était la suivante:

Dans le ViewController que vous masquez la navigationBar,

class MyNoNavBarViewController: UIViewController {
    
    // needed for reference when leaving this view controller
    var initialInteractivePopGestureRecognizerDelegate: UIGestureRecognizerDelegate?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // we will need a reference to the initial delegate so that when we push or pop.. 
        // ..this view controller we can appropriately assign back the original delegate
        initialInteractivePopGestureRecognizerDelegate = self.navigationController?.interactivePopGestureRecognizer?.delegate
    }

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

        // we must set the delegate to nil whether we are popping or pushing to..
        // ..this view controller, thus we set it in viewWillAppear()
        self.navigationController?.interactivePopGestureRecognizer?.delegate = nil
    }

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

        // and every time we leave this view controller we must set the delegate back..
        // ..to what it was originally
        self.navigationController?.interactivePopGestureRecognizer?.delegate = initialInteractivePopGestureRecognizerDelegate
    }
}

D'autres réponses suggèrent simplement de fixer le délégué à zéro. Glisser vers l'arrière vers le contrôleur de vue initial sur la pile de navigation entraîne la désactivation de tous les gestes. Une sorte de surveillance, peut-être, des développeurs UIKit / UIGesture.

De plus, certaines réponses que j'ai implémentées ici ont abouti à un comportement de navigation Apple non standard (en particulier, permettant la possibilité de faire défiler vers le haut ou vers le bas tout en glissant vers l'arrière). Ces réponses semblent également un peu verbeuses et dans certains cas incomplètes.

CodyB
la source
viewDidLoad()n'est pas un bon endroit pour capturer initialInteractivePopGestureRecognizerDelegatecar cela navigationControllerpourrait être nul (pas encore poussé sur la pile). viewWillAppearde l'endroit où vous
cachez la
10

En m'appuyant sur la réponse de Hunter Maximillion Monk , j'ai créé une sous-classe pour UINavigationController, puis défini la classe personnalisée pour mon UINavigationController dans mon storyboard. Le code final des deux classes ressemble à ceci:

InteractivePopRecognizer:

class InteractivePopRecognizer: NSObject {

    // MARK: - Properties

    fileprivate weak var navigationController: UINavigationController?

    // MARK: - Init

    init(controller: UINavigationController) {
        self.navigationController = controller

        super.init()

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

extension InteractivePopRecognizer: UIGestureRecognizerDelegate {
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return (navigationController?.viewControllers.count ?? 0) > 1
    }

    // This is necessary because without it, subviews of your top controller can cancel out your gesture recognizer on the edge.
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
}

HiddenNavBarNavigationController:

class HiddenNavBarNavigationController: UINavigationController {

    // MARK: - Properties

    private var popRecognizer: InteractivePopRecognizer?

    // MARK: - Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()
        setupPopRecognizer()
    }

    // MARK: - Setup

    private func setupPopRecognizer() {
        popRecognizer = InteractivePopRecognizer(controller: self)
    }
}

Storyboard:

Classe personnalisée du contrôleur de navigation Storyboard

tylermilner
la source
8

On dirait que la solution fournie par @ChrisVasseli est la meilleure. J'aimerais fournir la même solution en Objective-C car la question concerne Objective-C (voir les balises)

@interface InteractivePopGestureDelegate : NSObject <UIGestureRecognizerDelegate>

@property (nonatomic, weak) UINavigationController *navigationController;
@property (nonatomic, weak) id<UIGestureRecognizerDelegate> originalDelegate;

@end

@implementation InteractivePopGestureDelegate

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if (self.navigationController.navigationBarHidden && self.navigationController.viewControllers.count > 1) {
        return YES;
    } else {
        return [self.originalDelegate gestureRecognizer:gestureRecognizer shouldReceiveTouch:touch];
    }
}

- (BOOL)respondsToSelector:(SEL)aSelector
{
    if (aSelector == @selector(gestureRecognizer:shouldReceiveTouch:)) {
        return YES;
    } else {
        return [self.originalDelegate respondsToSelector:aSelector];
    }
}

- (id)forwardingTargetForSelector:(SEL)aSelector
{
    return self.originalDelegate;
}

@end

@interface NavigationController ()

@property (nonatomic) InteractivePopGestureDelegate *interactivePopGestureDelegate;

@end

@implementation NavigationController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.interactivePopGestureDelegate = [InteractivePopGestureDelegate new];
    self.interactivePopGestureDelegate.navigationController = self;
    self.interactivePopGestureDelegate.originalDelegate = self.interactivePopGestureRecognizer.delegate;
    self.interactivePopGestureRecognizer.delegate = self.interactivePopGestureDelegate;
}

@end
Timur Bernikovitch
la source
3
Parce qu'ObjC n'est pas encore mort! 😉
MonsieurDart
2
C'est la bonne solution. Toute autre solution qui ne transfère pas au délégué d'origine est incorrecte.
Josh Bernfeld
6

Ma solution est d'étendre directement la UINavigationControllerclasse:

import UIKit

extension UINavigationController: UIGestureRecognizerDelegate {

    override open func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        self.interactivePopGestureRecognizer?.delegate = self
    }

    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return self.viewControllers.count > 1
    }

}

De cette façon, tous les contrôleurs de navigation pourront être supprimés en glissant.

fredericdnd
la source
Curieusement, cela fait viewDidAppearignorer tous les appels sur les VC appartenant à n'importe quel contrôleur de navigation.
cumanzor
4

Vous pouvez le faire avec un délégué proxy. Lorsque vous créez le contrôleur de navigation, saisissez le délégué existant. Et transmettez-le au proxy. Passez ensuite toutes les méthodes de délégué au délégué existant, sauf en gestureRecognizer:shouldReceiveTouch:utilisantforwardingTargetForSelector:

Installer:

let vc = UIViewController(nibName: nil, bundle: nil)
let navVC = UINavigationController(rootViewController: vc)
let bridgingDelegate = ProxyDelegate()
bridgingDelegate.existingDelegate = navVC.interactivePopGestureRecognizer?.delegate
navVC.interactivePopGestureRecognizer?.delegate = bridgingDelegate

Délégué proxy:

class ProxyDelegate: NSObject, UIGestureRecognizerDelegate {
    var existingDelegate: UIGestureRecognizerDelegate? = nil

    override func forwardingTargetForSelector(aSelector: Selector) -> AnyObject? {
        return existingDelegate
    }

    func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
        return true
    }  
}
Nathan Perry
la source
Cette réponse est le vrai style Obj-C!
Sound Blaster
forwardingTargetForSelector m'aurait fait gagner tellement de temps sur un projet antérieur si j'avais su. Bon produit!
VaporwareWolf
4

La réponse de Hunter Monk est vraiment géniale, mais malheureusement dans iOS 13.3.1, cela ne fonctionne pas.

Je vais vous expliquer une autre façon de se cacher UINavigationBaret de ne pas perdre swipe to back gesture. J'ai testé sur iOS 13.3.1 et 12.4.3 et cela fonctionne.

Vous devez créer une classe personnalisée UINavigationControlleret définir cette classe pour UINavigationControllerdansStoryboard

Définissez la classe personnalisée sur <code> UINavigationController </code>

Ne cachez PAS NavigationBarleStoryboard

<code> UINavigationController </code> Inspecteur d'attributs:

Exemple sur Storyboard:

Storyboard:

Et enfin, mettre ceci: navigationBar.isHidden = truedans viewDidLoadde CustomNavigationControllerclasse.

Assurez-vous de ne PAS utiliser cette méthode setNavigationBarHidden(true, animated: true)pour masquer le fichier NavigationBar.

import UIKit

class CustomNavigationController: UINavigationController {

    override func viewDidLoad() {
        super.viewDidLoad()

        navigationBar.isHidden = true
    }
}
Jusuf Saiti
la source
2
J'ai testé cela sur un appareil réel iPhone 6S Plus avec iOS 13.4.1et faites glisser vers l'arrière fonctionne.
Emre Aydin le
1
fonctionne également sur le dernier iOS 14.0.1
bezoadam
1

Réponse Xamarin:

Implémentez l' IUIGestureRecognizerDelegateinterface dans la définition de classe de votre ViewController:

public partial class myViewController : UIViewController, IUIGestureRecognizerDelegate

Dans votre ViewController, ajoutez la méthode suivante:

[Export("gestureRecognizerShouldBegin:")]
public bool ShouldBegin(UIGestureRecognizer recognizer) {
  if (recognizer is UIScreenEdgePanGestureRecognizer && 
      NavigationController.ViewControllers.Length == 1) {
    return false;
  }
  return true;
}

Dans votre ViewController, ViewDidLoad()ajoutez la ligne suivante:

NavigationController.InteractivePopGestureRecognizer.Delegate = this;
Ahmad
la source
Cela se trouve probablement dans le UINavigationControllercontrôleur de vue racine du? J'obtiens le EXEC_BAD_ACCESSquand j'essaye ça.
Benjohn
Vous êtes capable de faire un panoramique sur le contrôleur de vue racine? Cela ne devrait pas être possible car lorsque vous êtes au niveau du VC racine, vous avez sauté tous les autres VC, et la longueur du tableau VC de votre Nav devrait être de 1.
Ahmad
Le crash se produit avant l'appel à gestureRecognizerShouldBegin:.
Benjohn
1
Pouvez-vous publier votre code VC dans une nouvelle question ou sur des forums Xamarin?
Ahmad
Non, je ne l'ai pas. Je pense que je vais le laisser pour .1!
Benjohn
1

J'ai essayé cela et cela fonctionne parfaitement: Comment masquer la barre de navigation sans perdre la capacité de retour en arrière

L'idée est d'implémenter "UIGestureRecognizerDelegate" dans votre .h et de l'ajouter à votre fichier .m.

- (void)viewWillAppear:(BOOL)animated {
// hide nav bar
[[self navigationController] setNavigationBarHidden:YES animated:YES];

// enable slide-back
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
    self.navigationController.interactivePopGestureRecognizer.enabled = YES;
    self.navigationController.interactivePopGestureRecognizer.delegate = self;
  }
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
   return YES;  
}
KarimIhab
la source
1

Voici ma solution: je change alpha sur la barre de navigation, mais la barre de navigation n'est pas masquée. Tous mes contrôleurs de vue sont une sous-classe de mon BaseViewController, et là j'ai:

    override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    navigationController?.navigationBar.alpha = 0.0
}

Vous pouvez également sous-classer UINavigationController et y placer cette méthode.

Mladen Ivastinovic
la source
0

Certaines personnes ont eu du succès en appelant la setNavigationBarHiddenméthode avec animated à la YESplace.

Mundi
la source
Je n'ai pas tenté de chance. Mise à jour de ma réponse pour couvrir cette suggestion.
mihai
0

Dans mon contrôleur de vue sans barre de navigation, j'utilise

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

  CATransaction.begin()
  UIView.animate(withDuration: 0.25, animations: { [weak self] in
    self?.navigationController?.navigationBar.alpha = 0.01
  })
  CATransaction.commit()
}

open override func viewWillDisappear(_ animated: Bool) {
  super.viewWillDisappear(animated)
  CATransaction.begin()
  UIView.animate(withDuration: 0.25, animations: { [weak self] in
    self?.navigationController?.navigationBar.alpha = 1.0
  })
  CATransaction.commit()
}

Pendant le rejet interactif, le bouton de retour brillera cependant, c'est pourquoi je l'ai caché.

fruitcoder
la source
-2

Il existe une solution vraiment simple que j'ai essayée et qui fonctionne parfaitement, c'est dans Xamarin.iOS mais peut également être appliquée en natif:

    public override void ViewWillAppear(bool animated)
    {
        base.ViewWillAppear(animated);
        this.NavigationController.SetNavigationBarHidden(true, true);
    }

    public override void ViewDidAppear(bool animated)
    {
        base.ViewDidAppear(animated);
        this.NavigationController.SetNavigationBarHidden(false, false);
        this.NavigationController.NavigationBar.Hidden = true;
    }

    public override void ViewWillDisappear(bool animated)
    {
        base.ViewWillDisappear(animated);
        this.NavigationController.SetNavigationBarHidden(true, false);
    }
João Palma
la source
-6

Voici comment désactiver la reconnaissance de gestes lorsque l'utilisateur glisse hors de ViewController. Vous pouvez le coller sur votre viewWillAppear () ou sur vos méthodes ViewDidLoad ().

if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
    self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
Eddwin Paz
la source
Veuillez lire la question avant de publier des réponses. La question était de l'activer, pas de la désactiver. NOUS ADORONS LE GESTURE POP.
Yogesh Maheshwari