İOS 7'de UINavigationController'da geri kaydırma hareketini devre dışı bırakma


326

İOS 7'de Apple yeni bir varsayılan gezinme davranışı ekledi. Gezinme yığınına geri dönmek için ekranın sol kenarından hızlıca kaydırabilirsiniz. Ancak uygulamamda, bu davranış özel sol menümle çakışıyor. Peki, bu yeni hareketi UINavigationController'da devre dışı bırakmak mümkün mü?



2
Ayrıca navigationItem.hidesBackButton = true, belirlerseniz , bu hareketin de devre dışı bırakıldığını öğrendim . Benim durumumda ben özel bir geri düğmesine uygulanan ve bir olarak eklemekleftBarButtonItem
Umeyr

Yanıtlar:


586

Bir çözüm buldum:

Objective-C:

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

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


29
Tabii ki, iOS'un eski sürümlerini destekliyorsanız yeni yöntemlerin kullanılabilirliğini kontrol etmeniz gerekir.
ArtFeel

2
Görüş iksiri için devre dışı bırakmanın bir yolu var mı?
Marc

11
/ enable / disableÜzerinde tanıyıcı kullanabilirsiniz . Veya, daha karmaşık mantığınızla protokolü uygulayabilir ve onu özellik olarak ayarlayabilirsiniz . viewDidAppear:viewDidDisappearUIGestureRecognizerDelegaterecognizer.delegate
ArtFeel

26
İOS8 günü, ayar self.navigationController.interactivePopGestureRecognizer.enabledözelliği görünümün yöntemler aşağıdaki çalışmaz: viewDidLoad, viewWillAppear, viewDidAppear, viewDidDisappear, ancak yöntemde çalışır viewWillDisappear. İOS7'de yukarıda belirtilen yöntemlerin hepsinde çalışır. Bu yüzden viewController üzerinde çalışırken diğer yöntemlerde kullanmaya çalışın, görünümün içindeki bazı düğmelere tıkladığımda iOS8'de benim için çalıştığını onaylıyorum.
Sihad Begovic

8
Bunun iOSD'de viewDidLoad ve viewWillAppear'da çalışmadığını onaylayabilir, viewwilllayoutgubviews içine koymak hile yaptı
tonytastic

47

Jestin sadece devre dışı olarak ayarlanmasının her zaman işe yaramadığını öğrendim. İşe yarıyor, ama benim için sadece bir kez sırtını kullandıktan sonra yaptı. İkinci kez geri çekmeyi tetiklemez.

Benim için düzeltme jest temsilci ve NO döndürmek için shouldbegin yöntemini uygulamak oldu:

- (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
Teşekkürler! Geri kaydırmayı tamamen devre dışı bırakmak için bu gereklidir. Hala iOS 8'de var ve bir Apple böceği gibi kokuyor.
Eric Chen

Teşekkür ederim, işe yarayan tek şey gibi görünüyor.
Ben

Neden bilmiyorum ama bazı bilinmeyen bir nedenden dolayı benim app bir görünüm denetleyicisi bu geri jest çöküyordu .. Bu geri jest gerek yoktu gibi bu beni kurtardı ve bu yüzden bu kodu kullanarak devre dışı .. +1
Ahsan Ebrahim

1
@AhsanEbrahim, arka hareket başladığında, viewWillAppeargeçerli görünümün arkasındaki görünümde çağrılır. Bu, geçerli görünüm hala etkin olduğundan kod mantığında hasara neden olabilir. Kazanın sebebi olabilir.
phatmann

Are enabledevet / hayır hatları gerekli? Geri NOdönüyorsun gestureRecognizerShouldBegin, bu yeterli değil mi?
ToolmakerSteve

30

Hareket algılayıcıyı NavigationController'dan kaldırın. İOS 8'de çalışın.

if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])
    [self.navigationController.view removeGestureRecognizer:self.navigationController.interactivePopGestureRecognizer];

ios 8 ve 9'da çalışan tek çözüm
Kappe

7
Ayrıca iOS 10'da çalışır, bu kabul edilen cevap olmalıdır. Bu arada, yeniden etkinleştirmek istiyorsanız, bir [self.navigationController.view addGestureRecognizer:self.navigationController.interactivePopGestureRecognizer]yerde yapın.
Ooops

22

İOS 8'den itibaren kabul edilen cevap artık çalışmıyor. Ana oyun ekranımda jest reddetmek için kaydırmayı durdurmak gerekiyordu bu yüzden bu uygulandı:

- (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
Bu iOS8 ile çalışırken * .delegate = self; belirleme: 'ViewController * const __strong' uyumsuz türünden <UIGestureRecognizerDelegate> 'kimliğine atama
David Douglas

2
İOS8'den itibaren, kabul edilen cevap hala beklendiği gibi çalışıyor. Muhtemelen yanlış bir şeyler yapıyorsunuz ..
Alexandre G

ViewWillLayoutSubviews içinde kabul edilen yanıtı çağırarak yarı çalışmayı başardı. Ancak, kaydırma işlemi sayfanın tekrar 'viewDidLoad' çağrılmasına neden oldu, bu yüzden yukarıdaki cevabım geri döndü
Charlie Seligman

@DavidDouglas: belki bu kodla uyarıyı ortadan kaldırabilirsiniz: __weak __typeof (self) theSafeSelf = self? Ardından delegeyi GüvenliGüvenliğe ayarlayın.
lifjoy

1
@DavidDouglas: Bu uyarıdan kurtulmak için arayüze <UIGestureRecognizerDelegate> eklemeniz gerekiyor
primehalo

20

Twan'ın cevabını biraz geliştirdim, çünkü:

  1. görünüm denetleyiciniz diğer hareket tanıyıcılara delege olarak atanmış olabilir
  2. nilKök görünümü denetleyicisine geri döndüğünüzde ve başka bir yere gitmeden önce hızlıca kaydırma hareketi yaptığınızda temsilci asmak sorunlara yol açar.

Aşağıdaki örnekte iOS 7 varsayılmıştır:

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

+1 "delegeyi sıfır olarak ayarlamak, kök görünüm denetleyicisine geri döndüğünüzde ve başka bir yere gitmeden önce hızlıca kaydırma hareketi yaptığınızda asılı sorunlara yol açar."
albertamg

10

Lütfen bunu root vc'de ayarlayın:

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

}

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

9

Swift için:

navigationController!.interactivePopGestureRecognizer!.enabled = false

12
Bu çalışır, ancak zorla açma yerine isteğe bağlı zincir kullanmanızı öneririm. örneğin self.navigationController? .interactivePopGestureRecognizer? .isEnabled = false
Womble

5

benim için ios 10 ve sonrasında çalışır:

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

}

viewDidLoad () yönteminde çalışmaz.


5

DÜZENLE

Belirli gezinme denetleyicileri için geri çekme özelliğini yönetmek istiyorsanız SwipeBack'i kullanmayı düşünün .

Bununla, ayarlayabilirsiniz navigationController.swipeBackEnabled = NO .

Örneğin:

#import <SwipeBack/SwipeBack.h>

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

CocoaPods üzerinden kurulabilir .

pod 'SwipeBack', '~> 1.0'

Açıklama eksikliğinden dolayı özür dilerim.


6
Katıldığınız bir projeyi tanıtırken, onunla olan ilişkinizi açıklamalısınız.

2
Ayrıca, projenizin tek amacı, varsayılan sistem çalışmadığında kaydırma hareketini manuel olarak etkinleştirmektir, oysa soru sistem genel hareketini nasıl devre dışı bırakacağınızı sorar, bu yüzden ayarlasanız bile self.navigationController.swipeBackEnabled = NObunun yalnızca kütüphanenin hızlıca geriye doğru hareketi ancak sisteminki etkin olmaya devam eder.

1
Kısa cevabım için üzgünüm, cevabımı ek bilgilerle düzenledim: "belirli navigasyon kontrolörleri için yararlı". Teşekkürler!
devxoul

Artık izin verilmeyen swizzle kullanıyor gibi görünüyor. iOS8?
Matt

1
@devxoul Özür dilerim! Kısa bir süre önce dolandırıcılığa artık izin verilmediğini söyleyerek bir şeyler okuduğumu sanıyordum. Ancak bunu söyleyen hiçbir şey bulamıyorum. Sanırım yanılıyorum.
Matt

4

Benim yöntemim. Hepsine hükmedecek bir hareket tanıyıcı:

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

Önemli: temsilciyi gezinme yığınında hiçbir yere sıfırlamayın: navigationController!.interactivePopGestureRecognizer!.delegate = nil


3

Swift 3'teki yol bu

benim için çalışıyor

    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false

3

Tüm bu çözümler Apple'ın jest tanıyıcısını tavsiye etmedikleri şekilde manipüle eder. Bana bir arkadaşımdan daha iyi bir çözüm olduğu söylendi:

[navigationController.interactivePopGestureRecognizer requireGestureRecognizerToFail: myPanGestureRecognizer];

myPanGestureRecognizer, örneğin menünüzü göstermek için kullandığınız hareket tanıyıcıdır. Bu şekilde, Apple'ın hareket tanıma cihazı yeni bir gezinme denetleyicisini ittiğinizde onlar tarafından tekrar açılmaz ve telefonunuz uykuya daldığında veya aşırı yük altındaysa çok erken patlayabilen çılgın gecikmelere güvenmeniz gerekmez.

Bunu burada bırakarak, bir dahaki sefere ihtiyacım olduğunda bunu hatırlamayacağımı biliyorum, ve sonra burada sorunun çözümü olacak.


3

swift 5, swift 4.2 aşağıdaki kodu kullanabilir.

// disable
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
// enable
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true

2

Verilen cevapların hiçbiri sorunu çözmeme yardımcı olmadı. Cevabımı buraya gönderiyorum; birisi için yardımcı olabilir

Beyan private var popGesture: UIGestureRecognizer?senin viewcontroller küresel değişken olarak. Sonra kodu viewDidAppear ve viewWillDisappear yöntemlerinde uygulayın

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

Bu, iOS v8.x sürümünden sonra hızlıca kaydırmayı devre dışı bırakacaktır


Bunun hangi koşullarda işe yarayacağını hayal etmeye çalışıyorum, ama Jack işe yaramadı. Diğer cevapların hepsini denediğinizi söylüyorsunuz: Jack'i denediğinizde neler ters gitti?
ToolmakerSteve

Öte yandan, bu Jack'inkinden daha basit görünüyor, bu yüzden belki de önemli değil. Bunu sevdiğime karar verdim, çünkü sınıfımı temsilci olarak ilan etmek veya manipüle etmek zorunda değilsiniz interactivePopGestureRecognizer.delegate.
ToolmakerSteve

BTW, kod basitleştirilebilir. Kaldır if( .. respondsToSelector ... Sonraki satır popGesture'u bir tanıyıcıya veya nil değerine ayarlar. Sonra değerini kullanın: if (self.popGesture != nil) self.navigationController .. removeGestureRecognizer( self.popGesture ).
ToolmakerSteve

2

Bu viewDidLoad:iOS 8 için çalışır :

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

Sorunların çoğu iyi ol 'yardımıyla çözülebilir dispatch_after.

Bu çözümün potansiyel olarak güvensiz olduğunu lütfen unutmayın, lütfen kendi mantığınızı kullanın.

Güncelleme

İOS 8.1 için gecikme süresi 0,5 saniye olmalıdır

İOS 9.3'te artık herhangi bir gecikmeye gerek yok, sadece bunu aşağıdakine yerleştirerek çalışır viewDidLoad:
(iOS 9.0-9.3 üzerinde çalışıyorsa TBD)

navigationController?.interactivePopGestureRecognizer?.enabled = false

Hareket algılayıcının görünümde ne zaman yüklendiğini bilmediğiniz sürece, devre dışı bırakmak için rasgele bir süre beklemek işe yarayabilir veya çalışmayabilir.
kalperin

@kalperin'in çalışması garanti edilmez, ancak bazen çok kullanışlı bir çözümdür. Kendi mantığınızı kullanın.
Dannie P


viewDidLoadartı gecikme riskli bir programlama uygulamasıdır. Başlamak için kötü bir alışkanlık. Gecikmeli aramanız başlamadan önce kullanıcı hızlıca kaydırmaya başlarsa ne olur? Yeterince uzun olduğu, ancak çok uzun olmadığı garanti edilen güvenli bir zaman yoktur. Bu yüzden sizinkinden çok önce gönderilen diğer yanıtlar kodu yerleştirmenizi önerir viewDidAppear. Bu, her şeyin kurulmasını sağlar. Keyfi gecikmeler icat etmeyin; Apple'ın arama sırasını istendiği gibi kullanın.
ToolmakerSteve

1
@ iChirag true. 8.1 için 0.5 saniye gecikmeye ihtiyacınız olduğunu belirttim
Dannie P

1

For Swift 4 bu çalışır:

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
    }

}

Belgelenmemiş davranışlara neden olacağı için etkileşimli pop jest temsilcisini geçersiz
kılmamalısınız

Sanırım gerçekten delege geçersiz kılmak değil, sadece bu amaç için sağladıkları Boole değişkenini değiştirmek, bu bir sorun olmayacak
Lok SN

0

Çoğu görüş denetleyicisi için benim için çalıştı.

self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false

UIPageViewController gibi bazı görünüm denetleyicileri için çalışmadı. UIPageViewController sayfasında pagecontentviewcontroller aşağıdaki kod benim için çalıştı.

override func viewDidLoad() {
   self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
   self.navigationController?.interactivePopGestureRecognizer?.delegate = self
}
override func viewWillDisappear(_ animated: Bool) {
   self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
   self.navigationController?.interactivePopGestureRecognizer?.delegate = nil
}

UIGestureRecognizerDelegate'te,

func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
   if gestureRecognizer == self.navigationController?.interactivePopGestureRecognizer {
      return false
}
      return true
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.