Cara menonaktifkan gesture gesek kembali di UINavigationController di iOS 7

326

Di iOS 7 Apple menambahkan perilaku navigasi default baru. Anda dapat menggesek dari tepi kiri layar untuk kembali ke tumpukan navigasi. Namun di aplikasi saya, perilaku ini bertentangan dengan menu kiri khusus saya. Jadi, apakah mungkin untuk menonaktifkan gerakan baru ini di UINavigationController?

ArtFeel
sumber
2
Saya juga mengetahui bahwa jika Anda mengatur navigationItem.hidesBackButton = true, gerakan ini juga dinonaktifkan. Dalam kasus saya, saya menerapkan tombol kembali kustom dan menambahkan sebagaileftBarButtonItem
Umair

Jawaban:

586

Saya menemukan solusinya:

Tujuan-C:

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

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

ArtFeel
sumber
29
Tentu saja, Anda perlu memeriksa ketersediaan metode baru jika Anda mendukung versi lama iOS.
ArtFeel
2
Apakah ada cara untuk menonaktifkannya untuk ramuan tampilan?
Marc
11
Anda dapat enable / disablemengenali di viewDidAppear:/ viewDidDisappear. Atau, Anda dapat mengimplementasikan UIGestureRecognizerDelegateprotokol dengan logika yang lebih kompleks dan menjadikannya sebagai recognizer.delegateproperti.
ArtFeel
26
Pada iOS8, pengaturan self.navigationController.interactivePopGestureRecognizer.enabledproperti tidak bekerja dalam mengikuti metode pandangan ini: viewDidLoad, viewWillAppear, viewDidAppear, viewDidDisappear, tetapi karya-karya dalam metode viewWillDisappear. Di iOS7 ia bekerja di semua metode yang disebutkan di atas. Jadi cobalah untuk menggunakannya dalam metode lain saat bekerja pada viewController, saya mengkonfirmasi itu berfungsi untuk saya di iOS8 ketika saya mengklik beberapa tombol di dalam tampilan.
Sihad Begovic
8
Dapat mengonfirmasi bahwa ini tidak akan berfungsi di iOS8 di viewDidLoad dan viewWillAppear, dengan memasukkannya ke viewwilllayoutgubviews, lakukan triknya
tonytastic
47

Saya menemukan bahwa pengaturan gestur menjadi dinonaktifkan hanya tidak selalu berhasil. Itu memang berhasil, tetapi bagi saya itu hanya terjadi setelah saya pernah menggunakan backgesture. Kedua kalinya itu tidak akan memicu backgesture.

Perbaiki untuk saya adalah mendelegasikan gerakan dan menerapkan metode shouldbegin untuk mengembalikan TIDAK:

- (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;
}
Antoine
sumber
1
Terima kasih! Ini diperlukan untuk sepenuhnya menonaktifkan gesekan kembali. Itu masih ada di iOS 8, dan baunya seperti bug Apple.
Eric Chen
Terima kasih, sepertinya menjadi satu-satunya hal yang berhasil.
Ben
Saya tidak tahu mengapa tetapi pengontrol tampilan di aplikasi saya untuk beberapa alasan yang tidak diketahui menabrak gerakan punggung ini .. ini menyelamatkan saya dari menemukannya karena saya tidak membutuhkan gerakan punggung ini dan jadi saya dinonaktifkan menggunakan kode ini .. +1
Ahsan Ebrahim
1
@AhsanEbrahim, ketika gerakan kembali dimulai, viewWillAppeardisebut pada tampilan belakang tampilan saat. Ini dapat menyebabkan kekacauan dalam logika kode karena tampilan saat ini masih aktif. Mungkin menjadi penyebab kecelakaan Anda.
phatmann
Apakah garis enabledya / tidak diperlukan? Anda kembali NOdari gestureRecognizerShouldBegin, bukankah itu cukup?
ToolmakerSteve
30

Hapus saja pengenal gesture dari NavigationController. Bekerja di iOS 8.

if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])
    [self.navigationController.view removeGestureRecognizer:self.navigationController.interactivePopGestureRecognizer];
Vladimir Samoylov
sumber
satu-satunya solusi yang benar-benar berfungsi di ios 8 dan 9
Kappe
7
Juga berfungsi di iOS 10, ini harus menjadi jawaban yang diterima. Omong-omong, jika Anda ingin mengaktifkannya kembali, lakukan di [self.navigationController.view addGestureRecognizer:self.navigationController.interactivePopGestureRecognizer]suatu tempat.
ooops
22

Pada iOS 8 jawaban yang diterima tidak lagi berfungsi. Saya perlu menghentikan swipping untuk mengabaikan gerakan di layar game utama saya jadi terapkan ini:

- (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;
}
Charlie Seligman
sumber
2
Sementara ini bekerja dengan iOS8 saya mendapatkan peringatan di baris * .delegate = self; menyatakan: Menetapkan ke id <UIGestureRecognizerDelegate> 'dari tipe yang tidak kompatibel' ViewController * const __strong '
David Douglas
2
Pada iOS8, jawaban yang diterima masih berfungsi seperti yang diharapkan. Anda mungkin melakukan sesuatu yang salah ..
Alexandre G
Berhasil membuatnya berfungsi dengan memanggil jawaban yang diterima di viewWillLayoutSubviews. Namun, menggesek memang menyebabkan halaman memanggil 'viewDidLoad' lagi sehingga kembali ke jawaban saya di atas
Charlie Seligman
@ Davidvidouglas: mungkin Anda bisa menghilangkan peringatan dengan kode ini: __weak __typeof (self) theSafeSelf = self? Kemudian atur delegasi ke SafeSelf.
Selamat bersenang
1
@DavidDouglas: Anda perlu menambahkan <UIGestureRecognizerDelegate> ke antarmuka untuk menghilangkan peringatan itu
primehalo
20

Saya sudah sedikit memperbaiki jawaban Twan, karena:

  1. pengontrol tampilan Anda dapat ditetapkan sebagai delegasi ke pengenal isyarat lain
  2. mengatur delegasi untuk nilmengarah ke masalah menggantung ketika Anda kembali ke pengontrol tampilan root dan melakukan gerakan gesek sebelum menavigasi di tempat lain.

Contoh berikut mengasumsikan iOS 7:

{
    id savedGestureRecognizerDelegate;
}

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

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

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer == self.navigationController.interactivePopGestureRecognizer) {
        return NO;
    }
    // add whatever logic you would otherwise have
    return YES;
}
Mendongkrak
sumber
+1 "menyetel delegasi ke nol mengarah ke masalah yang tergantung ketika Anda kembali ke pengontrol tampilan root dan melakukan gerakan gesek sebelum menavigasi di tempat lain."
albertamg
10

Silakan set ini di root vc:

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

}

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

Untuk Swift:

navigationController!.interactivePopGestureRecognizer!.enabled = false
iPhone 7
sumber
12
Ini bekerja, meskipun saya sarankan menggunakan chaining opsional alih-alih memaksa membuka. mis. self.navigationController? .interactivePopGestureRecognizer? .isEnabled = false
Womble
5

itu bekerja untuk saya di ios 10 dan yang lebih baru:

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

}

itu tidak bekerja pada metode viewDidLoad ().

Logika
sumber
5

EDIT

Jika Anda ingin mengelola fitur swipe back untuk pengontrol navigasi tertentu, pertimbangkan untuk menggunakan SwipeBack .

Dengan ini, Anda dapat mengatur navigationController.swipeBackEnabled = NO.

Sebagai contoh:

#import <SwipeBack/SwipeBack.h>

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

Itu dapat diinstal melalui CocoaPods .

pod 'SwipeBack', '~> 1.0'

Saya mohon maaf karena tidak ada penjelasan.

devxoul
sumber
6
Ketika mempromosikan suatu proyek Anda terlibat dengan Anda harus mengungkapkan afiliasi Anda dengannya.
2
Selain itu, satu-satunya tujuan proyek Anda adalah mengaktifkan gerakan gesek secara manual ketika sistem default tidak berfungsi, sedangkan pertanyaannya menanyakan cara menonaktifkan gerakan lebar sistem itu, jadi meskipun Anda mengaturnya, self.navigationController.swipeBackEnabled = NOsaya yakin ini hanya akan menonaktifkan Anda gerakan kembali perpustakaan menggesek tetapi sistem masih akan diaktifkan.
1
Maaf untuk jawaban singkat saya, saya baru saja mengedit jawaban saya dengan informasi tambahan: "berguna untuk pengontrol navigasi tertentu". Terima kasih!
devxoul
Tampaknya menggunakan swizzle yang tidak lagi diizinkan. iOS8?
Matt
1
@ evxoul saya minta maaf! Saya pikir saya telah membaca sesuatu beberapa waktu lalu yang mengatakan bahwa swizzling tidak lagi diizinkan. Namun, saya tidak dapat menemukan apa pun yang mengatakan ini. Kira saya salah.
Matt
4

Metode saya Satu pengenal isyarat untuk mengatur semuanya:

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

Penting: jangan mengatur ulang delegasi di mana pun di tumpukan navigasi: navigationController!.interactivePopGestureRecognizer!.delegate = nil

SoftDesigner
sumber
3

Ini adalah cara Swift 3

bekerja untukku

    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
Tayo119
sumber
3

Semua solusi ini memanipulasi pengenal gerakan Apple dengan cara yang tidak mereka rekomendasikan. Saya baru saja diberitahu oleh seorang teman bahwa ada solusi yang lebih baik:

[navigationController.interactivePopGestureRecognizer requireGestureRecognizerToFail: myPanGestureRecognizer];

di mana myPanGestureRecognizer adalah pengenal isyarat yang Anda gunakan untuk misalnya memperlihatkan menu Anda. Dengan begitu, pengenal isyarat Apple tidak bisa dihidupkan kembali oleh mereka ketika Anda mendorong pengontrol navigasi baru dan Anda tidak perlu bergantung pada penundaan hacky yang mungkin menyala terlalu awal jika ponsel Anda tertidur atau di bawah beban berat.

Meninggalkan ini di sini karena saya tahu saya tidak akan mengingat ini saat berikutnya saya membutuhkannya, dan kemudian saya akan memiliki solusi untuk masalah ini di sini.

uliwitness
sumber
3

swift 5, swift 4.2 dapat menggunakan kode di bawah ini.

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

Tidak satu pun dari jawaban yang diberikan membantu saya untuk menyelesaikan masalah. Posting jawaban saya di sini; semoga bermanfaat bagi seseorang

Deklarasikan private var popGesture: UIGestureRecognizer?sebagai variabel global dalam viewcontroller Anda. Kemudian implementasikan kode dalam metode viewDidAppear dan viewWillDisappear

override func viewDidAppear(animated: Bool) {

    super.viewDidAppear(animated)

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

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


override func viewWillDisappear(animated: Bool) {

    super.viewWillDisappear(animated)

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

Ini akan menonaktifkan gesek kembali di iOS v8.x dan seterusnya

Augustine PA
sumber
Saya mencoba membayangkan dalam keadaan apa ini akan berhasil, tetapi Jack tidak. Anda mengatakan Anda mencoba semua jawaban lain: apa yang salah ketika Anda mencoba Jack?
ToolmakerSteve
Di sisi lain, ini memang tampak lebih sederhana daripada Jack, jadi mungkin itu tidak penting. Memutuskan saya suka ini, karena tidak harus menyatakan kelas saya sebagai delegasi, atau memanipulasi interactivePopGestureRecognizer.delegate.
ToolmakerSteve
BTW, kode bisa disederhanakan. Hapus if( .. respondsToSelector ... Baris berikutnya mengatur popGesture ke sebuah pengenal, atau ke nol. Kemudian gunakan nilainya: if (self.popGesture != nil) self.navigationController .. removeGestureRecognizer( self.popGesture ).
ToolmakerSteve
2

Ini berfungsi viewDidLoad:untuk iOS 8:

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

Banyak masalah bisa diselesaikan dengan bantuan kebaikan dispatch_after.

Meskipun harap dicatat bahwa solusi ini berpotensi tidak aman, harap gunakan alasan Anda sendiri.

Memperbarui

Untuk iOS 8.1 waktu tunda harus 0,5 detik

Di iOS 9.3 tidak ada penundaan yang diperlukan lagi, ini berfungsi hanya dengan menempatkan ini di viewDidLoad:
(TBD jika bekerja di iOS 9.0-9.3)

navigationController?.interactivePopGestureRecognizer?.enabled = false
Dannie P
sumber
Kecuali Anda tahu kapan pengenal isyarat dipasang pada tampilan, menunggu jumlah waktu yang sewenang-wenang untuk menonaktifkannya mungkin atau mungkin tidak bekerja.
kalperin
@ kalperin itu tidak dijamin untuk bekerja, meskipun itu adalah solusi yang sangat berguna di beberapa waktu. Gunakan alasanmu sendiri.
Dannie P
Ini berfungsi untuk saya yang memiliki versi lebih besar dari iOS 8.1 :)
iChirag
viewDidLoadditambah penundaan adalah praktik pemrograman yang berisiko. Kebiasaan buruk untuk memulai. Bagaimana jika pengguna memulai swipe sebelum panggilan Anda yang tertunda masuk? Tidak ada waktu aman yang dijamin cukup lama namun tidak terlalu lama. Itulah sebabnya jawaban lain, yang diposting jauh sebelum Anda, menyarankan untuk memasukkan kode viewDidAppear. Itu memastikan semuanya terpasang. Jangan menciptakan penundaan yang sewenang-wenang; gunakan urutan panggilan Apple sebagaimana dimaksud.
ToolmakerSteve
1
@ iChirag benar. Saya telah mencatat bahwa untuk 8.1 Anda perlu penundaan 0,5 detik
Dannie P
1

Untuk Swift 4 ini berfungsi:

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
    }

}
Mat0
sumber
Anda tidak boleh mengesampingkan delegasi gerakan pop interaktif karena akan menyebabkan perilaku tidak berdokumen
Josh Bernfeld
Saya pikir itu tidak benar-benar mengesampingkan delegasi tetapi hanya memodifikasi variabel Boolean yang telah mereka sediakan untuk tujuan ini, jadi itu tidak akan menjadi masalah
Lok SN
0

Itu bekerja untuk saya untuk sebagian besar viewcontrollers.

self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false

Itu tidak berfungsi untuk beberapa viewcontrollers seperti UIPageViewController. Pada pagecontentviewcontroller UIPageViewController kode di bawah ini bekerja untuk saya.

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
}

Pada UIGestureRecognizerDelegate,

func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
   if gestureRecognizer == self.navigationController?.interactivePopGestureRecognizer {
      return false
}
      return true
}
Faris Muhammed
sumber