Kein Zurückwischen beim Ausblenden der Navigationsleiste in UINavigationController

86

Ich liebe das Swipe Pack, das durch das Einbetten Ihrer Ansichten in a geerbt wurde UINavigationController. Leider kann ich keinen Weg finden, das zu verbergen, NavigationBaraber ich habe immer noch die Touch-Pan-Wischfunktion zurück gesture. Ich kann benutzerdefinierte Gesten schreiben, aber ich ziehe es vor, mich stattdessen nicht auf das UINavigationControllerZurückwischen gesturezu verlassen.

Wenn ich es im Storyboard deaktiviere, funktioniert das Zurückwischen nicht

Geben Sie hier die Bildbeschreibung ein

alternativ, wenn ich es programmgesteuert verstecke, das gleiche Szenario.

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

Gibt es keine Möglichkeit, das Oberteil zu verstecken NavigationBarund trotzdem zu wischen?

mihai
quelle
1
Ist das Hinzufügen eines UIGestureRecognizer akzeptabel? Die Implementierung ist ein Kinderspiel.
SwiftArchitect
1
@LancelotdelaMare, ich habe versucht, das zu vermeiden, da es nicht so reibungslos funktioniert wie der UINavigationController Back Swipe. Ich schaue in UIScreenEdgePanGestureRecognizer, da einige Leute sagen, dass es hilft, aber es noch nicht zum Laufen gebracht hat. Suchen Sie hier nach der einfachsten und elegantesten Lösung.
Mihai

Antworten:

96

Ein Hack, der funktioniert, besteht darin, den interactivePopGestureRecognizerDelegierten des zu setzen , um Folgendes UINavigationControllerzu nilmögen:

[self.navigationController.interactivePopGestureRecognizer setDelegate:nil];

In einigen Situationen kann es jedoch zu seltsamen Effekten kommen.

HorseT
quelle
15
"Wiederholtes Zurückwischen kann dazu führen, dass die Geste erkannt wird, wenn sich nur ein Ansichts-Controller auf dem Stapel befindet, wodurch eine Benutzeroberfläche in einen (meiner Meinung nach von UIKit-Ingenieuren unerwarteten) Zustand versetzt wird, in dem keine Gesten mehr erkannt werden"
HorseT
4
Eine Alternative , die gegen diesen unerwarteten Zustand schützen könnte , wäre es zu einem gewissen Low-Level - Objekt zu setzen (ich meine AppDelegate verwendet) und implementieren gestureRecognizerShouldBegin, die Rückkehr , truewenn die navigationController‚s viewControllerZahl größer als 0
Kenny Winker
4
Obwohl dies funktioniert, empfehle ich dringend. Das Brechen des Delegaten verursachte einen seltenen und schwer zu identifizierenden Haupt-Thread-Block. Es stellt sich heraus, dass es kein Haupt-Thread-Block ist, sondern das, was @HorseT beschrieben hat.
Josh Bernfeld
3
Meine App speichert das Delegate-Handle und stellt es dann wieder her viewWillDisappear Bisher sind keine nachteiligen Nebenwirkungen aufgetreten.
Don Park
1
!!!! Es wird dringend davon abgeraten, diese Lösung zu verwenden, wenn bei wiederholter Verwendung von Swipe ein seltsames Verhalten auftritt, der Rücken deaktiviert ist und die gesamte App nicht mehr reagiert
KarimIhab
77

Probleme mit anderen Methoden

Das Einstellen von interactivePopGestureRecognizer.delegate = nilhat unbeabsichtigte Nebenwirkungen.

Die Einstellung navigationController?.navigationBar.hidden = truefunktioniert, lässt jedoch nicht zu, dass Ihre Änderung in der Navigationsleiste ausgeblendet wird.

Schließlich ist es im Allgemeinen besser, ein Modellobjekt zu erstellen, das UIGestureRecognizerDelegatefür Ihren Navigationscontroller geeignet ist. Das Festlegen auf einen Controller im UINavigationControllerStapel verursacht die EXC_BAD_ACCESSFehler.

Vollständige Lösung

Fügen Sie diese Klasse zunächst Ihrem Projekt hinzu:

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

Stellen Sie dann Ihren Navigationscontroller interactivePopGestureRecognizer.delegateauf eine Instanz Ihrer neuen InteractivePopRecognizerKlasse ein.

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
}

Genießen Sie eine versteckte Navigationsleiste ohne Nebenwirkungen, die auch dann funktioniert, wenn Ihr oberster Controller über Unteransichten für Tabellen-, Sammlungs- oder Bildlaufansichten verfügt.

Jägermönch
quelle
1
Tolle Lösung!
Matt Butler
1
Die beste Antwort, Danke!
Dory Daniel
2
@ HunterMaximillionMonk danke für die tolle Lösung. Es funktioniert wie ein Zauber
wie
1
@ HunterMaximillionMonk das scheint richtig zu funktionieren, aber das Problem damit, wenn ich mehrere Controller habe, dann nach einem einmaligen Pop funktioniert es nicht mehr.
Premal Khetani
1
Auf jeden Fall die beste Antwort!
daxh
55

In meinem Fall, um seltsame Effekte zu verhindern

Root View Controller

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
quelle
2
Manchmal bekomme ich EXC_BAD_ACCESS, wenn ich das benutze
Andrey Gordeev
Für mich macht es die Geste nicht zum EXEC_BAD_ACCESS
Laufen
2
Denken Sie daran UIGestureRecognizerDelegate, dem Root-View-Controller etwas hinzuzufügen ... In meinem Fall wurde der Delegat in einem späteren View-Controller auf Null gesetzt als der Root-View-Controller. Bei der Rückkehr zum Root-View-Controller gestureRecognizerShouldBeginwurde er also nicht aufgerufen. Also habe ich das .delegate = selfin platziert viewDidAppear(). Das löste die seltsamen Effekte in meinem Fall. Prost!
Wiingaard
@AndreyGordeev Könnten Sie bitte einige Details darüber angeben, wann EXEC_BAD_ACCESSdies geschieht?
Jaybo
Hier sind weitere Informationen über EXC_BAD_ACCESSFehler: stackoverflow.com/questions/28746123/…
Andrey Gordeev
25

Aktualisiert für iOS 13.4

iOS 13.4 hat die vorherige Lösung gebrochen, daher werden die Dinge hässlich. Es sieht so aus, als würde dieses Verhalten in iOS 13.4 jetzt von einer privaten Methode gesteuert _gestureRecognizer:shouldReceiveEvent:(nicht zu verwechseln mit der neuen öffentlichen shouldReceiveMethode, die in iOS 13.4 hinzugefügt wurde).


Ich stellte fest, dass andere veröffentlichte Lösungen, die den Delegaten überschrieben oder auf Null setzten, ein unerwartetes Verhalten verursachten.

In meinem Fall schlug es (wie erwartet) fehl, wenn ich mich oben auf dem Navigationsstapel befand und versuchte, mit der Geste eine weitere zu öffnen, aber nachfolgende Versuche, auf den Stapel zu drücken, verursachten seltsame grafische Störungen im Navigationsleiste. Dies ist sinnvoll, da der Delegat nicht nur verwendet wird, um zu verhindern, dass die Geste erkannt wird, wenn die Navigationsleiste ausgeblendet ist, und das gesamte andere Verhalten verworfen wird.

Aus meinen Tests geht hervor, dass dies gestureRecognizer(_:, shouldReceiveTouch:)die Methode ist, die der ursprüngliche Delegat implementiert, um zu verhindern, dass die Geste erkannt wird, wenn die Navigationsleiste ausgeblendet ist, nicht gestureRecognizerShouldBegin(_:). Andere Lösungen, die gestureRecognizerShouldBegin(_:)in ihrer Delegiertenarbeit implementiert gestureRecognizer(_:, shouldReceiveTouch:)werden, weil das Fehlen einer Implementierung von das Standardverhalten beim Empfangen aller Berührungen verursacht.

Die Lösung von @Nathan Perry kommt nahe, aber ohne eine Implementierung von respondsToSelector(_:)wird der UIKit-Code, der Nachrichten an den Delegierten sendet, glauben, dass es keine Implementierung für eine der anderen Delegatenmethoden gibt, undforwardingTargetForSelector(_:) wird niemals aufgerufen.

Wir übernehmen also die Kontrolle über `gestureRecognizer (_:, shouldReceiveTouch :) in dem einen bestimmten Szenario, in dem wir das Verhalten ändern möchten, und leiten ansonsten alles andere an den Delegaten weiter.

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
quelle
1
Sieht so aus, als wäre Ihre Lösung die beste für diesen Moment. Vielen Dank!
Timur Bernikovich
"Aber nachfolgende Versuche, auf den Stapel zu schieben, würden seltsame grafische Störungen in der Navigationsleiste verursachen" - ich bin hier verwirrt. Ich dachte wir hätten keine Navigationsleiste? Das ist die Frage? In meiner Situation ist ein Navigationscontroller als untergeordneter Ansichtscontroller ohne Navigationsleiste eingebettet. Das enthaltene VC verfügt über die Navigationssteuerung. Also habe ich den enthaltenden VC zum Delegierten des Erkenners gemacht und einfach das gestureRecognizerShouldBegin:Ding gemacht, und es "scheint zu funktionieren". Ich frage mich, worauf ich achten sollte.
Skagedal
2
Dies hatte einen Speicherverlust, da dies navigationControllereine starke Referenz im AlwaysPoppableDelegate war. Ich habe den Code bearbeitet, um dies als weakReferenz zu verwenden.
Graham Perks
3
Diese nette Lösung funktioniert nicht mehr in iOS 13.4
Ely
@ ChrisVasselli Wirklich super, danke! Hoffentlich besteht dies die Prüfung der privaten Methoden der App Store-Überprüfung.
Ely
16

Sie können UINavigationController wie folgt unterordnen:

@interface CustomNavigationController : UINavigationController<UIGestureRecognizerDelegate>

@end

Implementierung:

@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
quelle
2
Wenn Sie diesen Ansatz verwenden, wird die Pop-Geste beim UIPageViewControllerOverscroll unterbrochen.
Atulkhatri
Ich fand, dass viewController.count> 1 Prüfung notwendig ist. Wenn der Benutzer versucht, nur mit der Root-VC zurückzuwischen, bleibt die Benutzeroberfläche beim nächsten VC-Push hängen.
VaporwareWolf
11

Einfache Antwort ohne Nebenwirkungen

Während die meisten Antworten hier gut sind, haben sie scheinbar unbeabsichtigte Nebenwirkungen (App Breaking) oder sind ausführlich.

Die einfachste und zugleich funktionellste Lösung, die ich finden konnte, war die folgende:

In dem ViewController, in dem Sie die Navigationsleiste verstecken,

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

Andere Antworten haben vorgeschlagen, den Delegierten lediglich auf Null zu setzen. Wenn Sie rückwärts zum ursprünglichen Ansichts-Controller auf dem Navigationsstapel wischen, werden alle Gesten deaktiviert. Vielleicht eine Art Versehen der UIKit / UIGesture-Entwickler.

Außerdem haben einige Antworten, die ich hier implementiert habe, zu einem nicht standardmäßigen Apple-Navigationsverhalten geführt (insbesondere die Möglichkeit, nach oben oder unten zu scrollen und gleichzeitig rückwärts zu wischen). Diese Antworten wirken auch etwas ausführlich und in einigen Fällen unvollständig.

CodyB
quelle
viewDidLoad()ist kein guter Ort zum Erfassen, initialInteractivePopGestureRecognizerDelegateda navigationControlleres dort null sein könnte (noch nicht auf den Stapel geschoben). viewWillAppearDer Ort, an dem Sie die Navigationsleiste verstecken, ist besser geeignet
nCod3d
9

Aufbauend auf der Antwort von Hunter Maximillion Monk ich eine Unterklasse für UINavigationController erstellt und dann die benutzerdefinierte Klasse für meinen UINavigationController in meinem Storyboard festgelegt. Der endgültige Code für die beiden Klassen sieht folgendermaßen aus:

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:

Benutzerdefinierte Klasse des Storyboard-Navigationscontrollers

tylermilner
quelle
8

Die von @ChrisVasseli bereitgestellte Lösung scheint die beste zu sein. Ich möchte dieselbe Lösung in Objective-C bereitstellen, da es sich bei der Frage um Objective-C handelt (siehe Tags).

@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 Bernikovich
quelle
3
Weil ObjC noch nicht tot ist! 😉
MonsieurDart
2
Dies ist die richtige Lösung. Jede andere Lösung, die nicht an den ursprünglichen Delegaten weitergeleitet wird, ist falsch.
Josh Bernfeld
6

Meine Lösung besteht darin, die UINavigationControllerKlasse direkt zu erweitern :

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
    }

}

Auf diese Weise können alle Navigationssteuerungen durch Schieben geschlossen werden.

fredericdnd
quelle
Seltsamerweise werden dadurch alle viewDidAppearAufrufe der VCs eines Navigationscontrollers ignoriert.
Cumanzor
4

Sie können dies mit einem Proxy-Delegaten tun. Wenn Sie den Navigationscontroller erstellen, greifen Sie auf den vorhandenen Delegaten zu. Und geben Sie es an den Proxy weiter. Übergeben Sie dann alle Delegatmethoden an den vorhandenen Delegaten, außer gestureRecognizer:shouldReceiveTouch:mitforwardingTargetForSelector:

Konfiguration:

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

Proxy-Delegierter:

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
quelle
Diese Antwort ist wahr Obj-C-Stil!
Sound Blaster
forwardingTargetForSelector hätte mir bei einem früheren Projekt so viel Zeit gespart, wenn ich davon gewusst hätte. Gutes Zeug!
VaporwareWolf
3

Die Antwort von Hunter Monk ist wirklich großartig, aber leider funktioniert es in iOS 13.3.1 nicht.

Ich werde einen anderen Weg erklären, sich zu verstecken UINavigationBarund nicht zu verlieren swipe to back gesture. Ich habe auf iOS 13.3.1 und 12.4.3 getestet und es funktioniert.

Sie müssen eine benutzerdefinierte Klasse von in erstellen UINavigationControllerund diese Klasse für UINavigationControllerin festlegenStoryboard

Setzen Sie die benutzerdefinierte Klasse auf <code> UINavigationController </ code>

Verstecke das NICHT NavigationBarauf demStoryboard

<code> UINavigationController </ code> Attributinspektor:

Beispiel zu Storyboard:

Storyboard:

Und zum Schluss noch: navigationBar.isHidden = trueIn viewDidLoadder CustomNavigationControllerKlasse.

Stellen Sie sicher, dass Sie diese Methode NICHT setNavigationBarHidden(true, animated: true)zum Ausblenden der verwenden NavigationBar.

import UIKit

class CustomNavigationController: UINavigationController {

    override func viewDidLoad() {
        super.viewDidLoad()

        navigationBar.isHidden = true
    }
}
Jusuf Saiti
quelle
2
Ich habe dies auf einem realen Gerät iPhone 6S Plus mit getestet iOS 13.4.1und Swipe Back funktioniert.
Emre Aydin
1

Xamarin Antwort:

Implementieren Sie die IUIGestureRecognizerDelegateSchnittstelle in die Klassendefinition Ihres ViewControllers:

public partial class myViewController : UIViewController, IUIGestureRecognizerDelegate

Fügen Sie in Ihrem ViewController die folgende Methode hinzu:

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

Fügen Sie in Ihrem ViewController ViewDidLoad()die folgende Zeile hinzu:

NavigationController.InteractivePopGestureRecognizer.Delegate = this;
Ahmad
quelle
Vermutlich ist dies im UINavigationControllerRoot View Controller? Ich bekomme das, EXEC_BAD_ACCESSwenn ich das versuche.
Benjohn
Sie können Pan auf dem Root View Controller kanten? Das sollte nicht möglich sein, denn wenn Sie am Root-VC sind, haben Sie alle anderen VCs gepoppt, und die Länge des VC-Arrays Ihres Nav sollte 1
Ahmad
Der Absturz tritt vor dem Aufruf von auf gestureRecognizerShouldBegin:.
Benjohn
1
Können Sie Ihren VC-Code in einer neuen Frage oder in Xamarin-Foren veröffentlichen?
Ahmad
Nein, habe ich nicht. Ich denke, ich lasse es für .1!
Benjohn
1

Ich habe es versucht und es funktioniert perfekt: So verstecken Sie die Navigationsleiste, ohne die Fähigkeit zum Zurückschieben zu verlieren

Die Idee ist, "UIGestureRecognizerDelegate" in Ihrer .h zu implementieren und diese zu Ihrer .m-Datei hinzuzufügen.

- (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
quelle
1

Hier ist meine Lösung: Ich ändere Alpha in der Navigationsleiste, aber die Navigationsleiste ist nicht ausgeblendet. Alle meine View Controller sind eine Unterklasse meines BaseViewControllers, und dort habe ich:

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

Sie können auch UINavigationController unterordnen und diese Methode dort ablegen.

Mladen Ivastinovic
quelle
0

Einige Leute hatten Erfolg, indem sie die setNavigationBarHiddenMethode YESstattdessen mit animierten aufgerufen haben.

Mundi
quelle
Ich habe kein Glück versucht. Aktualisierung meiner Antwort, um diesen Vorschlag abzudecken.
Mihai
0

In meinem View Controller ohne Navigationsleiste verwende ich

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()
}

Während der interaktiven Entlassung leuchtet der Zurück-Button jedoch durch, weshalb ich ihn versteckt habe.

Obstcodierer
quelle
-1

Es gibt eine wirklich einfache Lösung, die ich ausprobiert habe und die perfekt funktioniert. Sie befindet sich in Xamarin.iOS, kann aber auch auf native angewendet werden:

    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
quelle
-6

Hier erfahren Sie, wie Sie die Gestenerkennung deaktivieren, wenn der Benutzer den ViewController verlässt. Sie können es in Ihre viewWillAppear () - oder in Ihre ViewDidLoad () -Methoden einfügen.

if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
    self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
Eddwin Paz
quelle
Bitte lesen Sie die Frage, bevor Sie Antworten veröffentlichen. Die Frage war, es zu aktivieren, nicht zu deaktivieren. WIR LIEBEN DIE POP GESTURE.
Yogesh Maheshwari