Bez przesuwania do tyłu podczas ukrywania paska nawigacji w UINavigationController

86

Uwielbiam pakiet do przesuwania, który jest odziedziczony po osadzaniu widoków w pliku UINavigationController. Niestety nie mogę znaleźć sposobu, aby ukryć, NavigationBarale nadal mam przesuwanie panelu dotykowego z powrotem gesture. Mogę pisać niestandardowe gesty, ale wolę tego nie UINavigationControllerrobić i gesturezamiast tego polegać na przesunięciu w tył .

jeśli odznaczę to w scenorysie, przesunięcie w tył nie działa

wprowadź opis obrazu tutaj

alternatywnie, jeśli programowo to ukryję, ten sam scenariusz.

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

Czy nie ma sposobu, aby ukryć górę NavigationBari nadal mieć machnięcie?

mihai
źródło
1
Czy dodanie UIGestureRecognizer jest dopuszczalne? Wdrożenie jest bardzo proste.
SwiftArchitect,
1
@LancelotdelaMare, starałem się tego uniknąć, ponieważ nie będzie działać tak płynnie, jak przesunięcie wstecznego kontrolera UINavigationController. Zaglądam do UIScreenEdgePanGestureRecognizer, ponieważ niektórzy mówią, że pomaga, ale jeszcze nie udało mi się go uruchomić. Poszukuję tutaj najprostszego i najbardziej eleganckiego rozwiązania.
mihai,

Odpowiedzi:

96

Hack, który działa, polega na ustawieniu interactivePopGestureRecognizerdelegata w następujący UINavigationControllersposób nil:

[self.navigationController.interactivePopGestureRecognizer setDelegate:nil];

Ale w niektórych sytuacjach może to wywołać dziwne efekty.

Horse T.
źródło
16
„Wielokrotne przesuwanie do tyłu może spowodować rozpoznanie gestu, gdy na stosie jest tylko jeden kontroler widoku, co z kolei wprowadza interfejs użytkownika w stan (myślę, że nieoczekiwany przez inżynierów UIKit), w którym przestaje rozpoznawać gesty”
HorseT
4
Alternatywą, które mogą chronić przed tym nieoczekiwanym stanie byłoby ustawić go do jakiegoś przedmiotu niskopoziomowych (użyłem mojego app delegata) i wdrożyć gestureRecognizerShouldBegin, wracając truejeśli navigationControllerjest viewControllerliczba jest większa niż 0.
Kenny Winker
4
Chociaż to działa, BARDZO odradzam to. Przerwanie delegata powodowało rzadki i trudny do zidentyfikowania blok głównego wątku. Okazuje się, że nie jest to główny blok wątku, ale to, co opisał @HorseT.
Josh Bernfeld
3
Moja aplikacja zapisuje uchwyt delegata, a następnie przywraca go viewWillDisappeari jak dotąd nie wystąpiły żadne niepożądane skutki uboczne.
Don Park
1
!!!! Zdecydowanie odradzam korzystanie z tego rozwiązania, przy wielokrotnym korzystaniu z przeciągnięcia pojawia się dziwne zachowanie, tył jest wyłączony, a cała aplikacja nie reaguje
KarimIhab
79

Problemy z innymi metodami

Ustawienie interactivePopGestureRecognizer.delegate = nilma niezamierzone skutki uboczne.

Ustawienie navigationController?.navigationBar.hidden = truedziała, ale nie pozwala na ukrycie zmian w pasku nawigacji.

Na koniec ogólnie lepszą praktyką jest utworzenie obiektu modelu, który jest UIGestureRecognizerDelegateprzeznaczony dla kontrolera nawigacji. Ustawienie go na kontroler w UINavigationControllerstosie powoduje EXC_BAD_ACCESSbłędy.

Pełne rozwiązanie

Najpierw dodaj tę klasę do swojego projektu:

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

Następnie ustaw kontroler nawigacji na interactivePopGestureRecognizer.delegatewystąpienie nowej InteractivePopRecognizerklasy.

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
}

Ciesz się ukrytym paskiem nawigacji bez efektów ubocznych, który działa nawet wtedy, gdy Twój górny kontroler ma podglądy tabeli, kolekcji lub przewijania.

Hunter Monk
źródło
1
Świetne rozwiązanie!
Matt Butler,
1
Najlepsza odpowiedź, dzięki!
Dory Daniel
2
@HunterMaximillionMonk dzięki za świetne rozwiązanie. Działa jak urok
jak diu
1
@HunterMaximillionMonk wygląda na to, że działa poprawnie, ale problem z nim, gdy mam wiele kontrolerów, a następnie po jednym wyskoku przestaje działać.
Premal Khetani
1
Zdecydowanie najlepsza odpowiedź!
daxh
54

W moim przypadku, aby zapobiec dziwnym efektom

Główny kontroler widoku

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
źródło
2
Czasami dostaję EXC_BAD_ACCESS podczas używania tego
Andrey Gordeev
Dla mnie to nie sprawia, że ​​gest działa i często wywala się zEXEC_BAD_ACCESS
Benjohn
2
Pamiętaj, aby dodać UIGestureRecognizerDelegatedo głównego kontrolera widoku ... W moim przypadku delegat został ustawiony na zero w późniejszym kontrolerze widoku niż główny kontroler widoku, więc po powrocie do głównego kontrolera widoku gestureRecognizerShouldBeginnie został wywołany. Więc umieściłem .delegate = selfw viewDidAppear(). To rozwiązało dziwne efekty w moim przypadku… Na zdrowie!
Wiingaard
@AndreyGordeev Czy mógłbyś podać kilka szczegółów, kiedy to się EXEC_BAD_ACCESSstanie?
Jaybo,
Oto więcej informacji o EXC_BAD_ACCESSbłędzie: stackoverflow.com/questions/28746123/…
Andrey Gordeev
25

Zaktualizowano dla iOS 13.4

iOS 13.4 zepsuł poprzednie rozwiązanie, więc sprawy potoczą się brzydko. Wygląda na to, że w iOS 13.4 to zachowanie jest teraz kontrolowane przez metodę prywatną _gestureRecognizer:shouldReceiveEvent:(nie mylić z nową shouldReceivemetodą publiczną dodaną w iOS 13.4).


Okazało się, że inne opublikowane rozwiązania zastępujące delegata lub ustawienie go na zero spowodowały nieoczekiwane zachowanie.

W moim przypadku, gdy byłem na szczycie stosu nawigacyjnego i próbowałem użyć gestu, aby wyskoczyć jeszcze jeden, kończyło się to niepowodzeniem (zgodnie z oczekiwaniami), ale kolejne próby wepchnięcia na stos zaczęłyby powodować dziwne graficzne usterki w Pasek nawigacyjny. Ma to sens, ponieważ delegat jest używany do obsługi czegoś więcej niż tylko tego, czy blokować rozpoznawanie gestu, gdy pasek nawigacji jest ukryty, a wszystkie inne zachowania były odrzucane.

Z moich testów wynika, że gestureRecognizer(_:, shouldReceiveTouch:)jest to metoda, którą implementuje oryginalny delegat, aby zablokować rozpoznawanie gestu, gdy pasek nawigacji jest ukryty, a nie gestureRecognizerShouldBegin(_:). Inne rozwiązania, które zaimplementują gestureRecognizerShouldBegin(_:)w swojej pracy delegata, ponieważ brak implementacji gestureRecognizer(_:, shouldReceiveTouch:)spowoduje domyślne zachowanie wszystkich dotknięć.

Rozwiązanie @Nathana Perry'ego zbliża się, ale bez implementacji respondsToSelector(_:)kod UIKit, który wysyła wiadomości do delegata, będzie uważał, że nie ma implementacji dla żadnej innej metody delegata i forwardingTargetForSelector(_:)nigdy nie zostanie wywołany.

Więc przejmujemy kontrolę nad `gestRecognizer (_ :, shouldReceiveTouch :) w jednym konkretnym scenariuszu, w którym chcemy zmodyfikować zachowanie, iw przeciwnym razie przekazujemy wszystko inne do delegata.

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
źródło
1
Wygląda na to, że Twoje rozwiązanie jest najlepsze w tej chwili. Dzięki!
Timur Bernikovich
„ale kolejne próby wepchnięcia na stos zaczęłyby powodować dziwne błędy graficzne na pasku nawigacyjnym” - jestem zdezorientowany. Myślałem, że nie mamy paska nawigacji? Oto jest pytanie? W mojej sytuacji mam osadzony kontroler nawigacji jako podrzędny kontroler widoku bez paska nawigacyjnego; zawierający VC posiada elementy sterujące nawigacją. Pozwoliłem więc zawierającemu VC być delegatem modułu rozpoznającego i po prostu wykonałem to gestureRecognizerShouldBegin:, co „wydaje się działać”. Zastanawiam się, czy powinienem uważać.
skagedal
2
Miało to wyciek pamięci, ponieważ navigationControllerbył silnym odniesieniem w AlwaysPoppableDelegate. Edytowałem kod, aby uczynić go weakodniesieniem.
Graham Perks
3
To fajne rozwiązanie już nie działa w iOS 13.4
Ely
@ChrisVasselli Naprawdę niesamowite, dziękuję! Mamy nadzieję, że przejdzie to prywatna kontrola metod przeglądu App Store.
Ely
16

Możesz podklasę UINavigationController w następujący sposób:

@interface CustomNavigationController : UINavigationController<UIGestureRecognizerDelegate>

@end

Realizacja:

@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
źródło
2
Stosowanie tego podejścia jest przełamaniem gestu pop w UIPageViewControllerprzewijaniu.
atulkhatri
Zauważyłem, że sprawdzenie viewController.count> 1 jest konieczne. Jeśli użytkownik spróbuje przesunąć z powrotem tylko z głównym VC, interfejs użytkownika zawiesi się przy następnym naciśnięciu VC.
VaporwareWolf,
11

Prosta odpowiedź bez skutków ubocznych

Chociaż większość odpowiedzi tutaj jest dobra, pozornie mają one niezamierzone skutki uboczne (zepsute aplikacje) lub są szczegółowe.

Najprostszym, ale funkcjonalnym rozwiązaniem, jakie mogłem wymyślić, było:

W kontrolerze ViewController, w którym ukrywasz pasek nawigacji,

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

Inne odpowiedzi sugerowały jedynie ustawienie delegata na zero. Przeciągnięcie wstecz do początkowego kontrolera widoku na stosie nawigacyjnym powoduje wyłączenie wszystkich gestów. Być może jakieś niedopatrzenie twórców UIKit / UIGesture.

Ponadto niektóre odpowiedzi, które zaimplementowałem, zaowocowały niestandardowym zachowaniem nawigacji w jabłkach (w szczególności umożliwiając przewijanie w górę lub w dół, jednocześnie przesuwając palcem do tyłu). Te odpowiedzi również wydają się nieco rozwlekłe, a w niektórych przypadkach niepełne.

CodyB
źródło
viewDidLoad()nie jest dobrym miejscem do bicia, initialInteractivePopGestureRecognizerDelegateponieważ navigationControllermoże tam być zero (jeszcze nie trafiono na stos). viewWillAppearmiejsca, w którym ukrywasz pasek nawigacji, byłoby bardziej odpowiednie
nCod3d
10

Opierając się na odpowiedzi Huntera Maximillion Monk , utworzyłem podklasę dla UINavigationController, a następnie ustawiłem niestandardową klasę dla mojego UINavigationController w moim storyboardzie. Ostateczny kod obu klas wygląda następująco:

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:

Klasa niestandardowa kontrolera nawigacji scenorysu

tylermilner
źródło
8

Wygląda na to, że rozwiązanie dostarczone przez @ChrisVasseli jest najlepsze. Chciałbym zapewnić to samo rozwiązanie w Objective-C, ponieważ pytanie dotyczy Objective-C (zobacz tagi)

@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
źródło
3
Ponieważ ObjC jeszcze nie umarł! 😉
MonsieurDart,
2
To jest poprawne rozwiązanie. Każde inne rozwiązanie, które nie przesyła dalej do oryginalnego delegata, jest nieprawidłowe.
Josh Bernfeld
6

Moje rozwiązanie to bezpośrednie rozszerzenie UINavigationControllerklasy:

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
    }

}

W ten sposób wszystkie kontrolery nawigacyjne zostaną odrzucone przez przesuwanie.

fredericdnd
źródło
Co dziwne, powoduje viewDidAppearto ignorowanie wszystkich wywołań VC należących do dowolnego kontrolera nawigacyjnego.
cumanzor
4

Możesz to zrobić za pomocą pełnomocnika proxy. Podczas tworzenia kontrolera nawigacji pobierz istniejącego delegata. I przekaż go do proxy. Następnie przekaż wszystkie metody delegata do istniejącego delegata, z wyjątkiem gestureRecognizer:shouldReceiveTouch:usingforwardingTargetForSelector:

Ustawiać:

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

Pełnomocnik:

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
źródło
Ta odpowiedź jest prawdziwa w stylu Obj-C!
Sound Blaster
forwardingTargetForSelector zaoszczędziłoby mi tyle czasu przy poprzednim projekcie, gdybym o tym wiedział. Dobry towar!
VaporwareWolf,
4

Odpowiedź Hunter Monk jest naprawdę świetna, ale niestety w iOS 13.3.1 nie działa.

Wyjaśnię inny sposób, aby się ukryć UINavigationBari nie zgubić swipe to back gesture. Testowałem na iOS 13.3.1 i 12.4.3 i działa.

Trzeba utworzyć klasy niestandardowej UINavigationControlleri ustawić dla tej klasy UINavigationControllerwStoryboard

Ustaw klasę niestandardową na <code> UINavigationController </code>

NIE ukrywaj NavigationBarnaStoryboard

<code> UINavigationController </code> Inspektor atrybutów:

Przykład na Storyboard:

Storyboard:

I na koniec umieść to: navigationBar.isHidden = truein viewDidLoadof CustomNavigationControllerclass.

Upewnij się, że NIE używaj tej metody setNavigationBarHidden(true, animated: true)do ukrywania pliku NavigationBar.

import UIKit

class CustomNavigationController: UINavigationController {

    override func viewDidLoad() {
        super.viewDidLoad()

        navigationBar.isHidden = true
    }
}
Jusuf Saiti
źródło
2
Przetestowałem to na prawdziwym urządzeniu iPhone 6S Plus z iOS 13.4.1i przesuń palcem wstecz działa.
Emre Aydin
1
działa również na najnowszym iOS 14.0.1
bezoadam
1

Odpowiedź platformy Xamarin:

Zaimplementuj IUIGestureRecognizerDelegateinterfejs w definicji klasy ViewControllera:

public partial class myViewController : UIViewController, IUIGestureRecognizerDelegate

W swoim ViewController dodaj następującą metodę:

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

W kontrolerze ViewControllera ViewDidLoad()dodaj następujący wiersz:

NavigationController.InteractivePopGestureRecognizer.Delegate = this;
Ahmad
źródło
Przypuszczalnie jest to w UINavigationControllergłównym kontrolerze widoku? Dostaję, EXEC_BAD_ACCESSkiedy tego próbuję.
Benjohn,
Możesz przesuwać krawędź na głównym kontrolerze widoku? To nie powinno być możliwe, ponieważ kiedy jesteś w głównym VC, usunąłeś wszystkie inne VC, a długość tablicy VC twojego Nav powinna wynosić 1.
Ahmad
Awaria występuje przed wywołaniem gestureRecognizerShouldBegin:.
Benjohn
1
Czy możesz opublikować swój kod VC w nowym pytaniu lub na forach Xamarin?
Ahmad
Nie, nie mam. Myślę, że zostawię to na .1!
Benjohn
1

Wypróbowałem to i działa idealnie: jak ukryć pasek nawigacji bez utraty możliwości cofania

Chodzi o to, aby zaimplementować „UIGestureRecognizerDelegate” w swoim .h i dodać to do swojego pliku .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
źródło
1

Oto moje rozwiązanie: zmieniam alfę na pasku nawigacji, ale pasek nawigacji nie jest ukryty. Wszystkie moje kontrolery widoku są podklasą mojego BaseViewController i mam:

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

Możesz również utworzyć podklasę UINavigationController i umieścić tam tę metodę.

Mladen Ivastinovic
źródło
0

Niektórzy odnieśli sukces, nazywając setNavigationBarHiddenmetodę YESzamiast tego animated .

Mundi
źródło
Nie próbowałem szczęścia. Aktualizuję odpowiedź, aby uwzględnić tę sugestię.
mihai
0

W moim widoku kontroler bez paska nawigacyjnego używam

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

Podczas interaktywnej zwalniania przycisk powrotu będzie jednak przeświecał, dlatego go ukryłem.

fruitcoder
źródło
-2

Jest naprawdę proste rozwiązanie, które wypróbowałem i działa idealnie, jest w Xamarin.iOS, ale można je również zastosować do natywnych:

    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
źródło
-6

Oto jak wyłączyć rozpoznawanie gestów, gdy użytkownik wysuwa się z ViewController. Możesz wkleić go do swojej metody viewWillAppear () lub do metod ViewDidLoad ().

if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
    self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
Eddwin Paz
źródło
Przeczytaj pytanie przed wysłaniem odpowiedzi. Pytanie dotyczyło włączenia, a nie wyłączenia. KOCHAMY GEST POP.
Yogesh Maheshwari