Cách tắt cử chỉ vuốt ngược trong UINavestionControll trên iOS 7


326

Trong iOS 7, Apple đã thêm một hành vi điều hướng mặc định mới. Bạn có thể vuốt từ cạnh trái của màn hình để quay lại ngăn xếp điều hướng. Nhưng trong ứng dụng của tôi, hành vi này mâu thuẫn với menu bên trái tùy chỉnh của tôi. Vì vậy, có thể vô hiệu hóa cử chỉ mới này trong UINavestionControll không?



2
Tôi cũng phát hiện ra rằng nếu bạn đặt navigationItem.hidesBackButton = true, cử chỉ này cũng bị vô hiệu hóa. Trong trường hợp của tôi, tôi đã triển khai một nút quay lại tùy chỉnh và thêm dưới dạngleftBarButtonItem
Umair

Câu trả lời:


586

Tôi tìm thấy một giải pháp:

Mục tiêu-C:

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

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


29
Tất nhiên, bạn cần kiểm tra tính khả dụng của các phương thức mới nếu bạn đang hỗ trợ các phiên bản iOS cũ.
ArtFeel

2
Có cách nào để vô hiệu hóa nó cho một lọ thuốc xem không?
Marc

11
Bạn có thể enable / disablenhận dạng trên viewDidAppear:/ viewDidDisappear. Hoặc, bạn có thể thực hiện UIGestureRecognizerDelegategiao thức với logic phức tạp hơn của mình và đặt nó làm thuộc recognizer.delegatetính.
ArtFeel

26
Trên iOS8, thiết lập self.navigationController.interactivePopGestureRecognizer.enabledtài sản không hoạt động trong sau phương pháp quan điểm của: viewDidLoad, viewWillAppear, viewDidAppear, viewDidDisappear, nhưng các công trình trong phương pháp viewWillDisappear. Trên iOS7, nó hoạt động trong tất cả các phương pháp được đề cập ở trên. Vì vậy, hãy thử sử dụng nó trong bất kỳ phương thức nào khác trong khi làm việc trên viewContoder, tôi xác nhận nó hoạt động với tôi trên iOS8 khi tôi nhấp vào một số nút bên trong chế độ xem.
Sihad Begovic

8
Có thể xác nhận rằng điều này sẽ không hoạt động trong iOS8 trong viewDidLoad và viewWillAppear, đưa nó vào viewwilllayoutgubview đã thực hiện thủ thuật
tonytastic

47

Tôi phát hiện ra việc thiết lập cử chỉ thành vô hiệu hóa không phải lúc nào cũng hoạt động. Nó không hoạt động, nhưng đối với tôi, nó chỉ được thực hiện sau khi tôi sử dụng backesture. Lần thứ hai, nó sẽ không gây ra hậu quả.

Khắc phục đối với tôi là ủy thác cử chỉ và thực hiện phương thức Shouldbegin để trả về NO:

- (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
Cảm ơn! Điều này là cần thiết để vô hiệu hóa hoàn toàn vuốt ngược. Nó vẫn tồn tại trong iOS 8 và có mùi giống như lỗi của Apple.
Eric Chen

Cảm ơn bạn, dường như là điều duy nhất đã làm việc.
Ben

Tôi không biết tại sao nhưng một bộ điều khiển xem trong ứng dụng của tôi vì một số lý do không xác định đã bị hỏng ở cử chỉ quay lại này .. điều này đã giúp tôi không tìm thấy nó vì tôi không cần cử chỉ quay lại này và vì vậy tôi đã vô hiệu hóa bằng mã này .. +1
Ahsan Ebrahim

1
@AhsanEbrahim, khi cử chỉ quay lại bắt đầu, viewWillAppearđược gọi trên chế độ xem phía sau chế độ xem hiện tại. Điều này có thể gây ra sự tàn phá trong logic mã vì chế độ xem hiện tại vẫn đang hoạt động. Có thể là nguyên nhân của sự sụp đổ của bạn.
phatmann

enabledcó / không có dòng cần thiết? Bạn trở về NOtừ gestureRecognizerShouldBegin, không đủ?
ToolmakerSteve

30

Chỉ cần loại bỏ nhận dạng cử chỉ từ NavigationContoder. Làm việc trong iOS 8.

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

giải pháp duy nhất thực sự hoạt động trong ios 8 và 9
Kappe

7
Cũng hoạt động trong iOS 10, đây sẽ là câu trả lời được chấp nhận. Nhân tiện, nếu bạn muốn kích hoạt lại nó, hãy làm [self.navigationController.view addGestureRecognizer:self.navigationController.interactivePopGestureRecognizer]ở đâu đó.
ooops

22

Kể từ iOS 8, câu trả lời được chấp nhận không còn hoạt động. Tôi cần phải dừng việc vuốt để loại bỏ cử chỉ trên màn hình trò chơi chính của mình để thực hiện điều này:

- (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
Trong khi điều này hoạt động với iOS8, tôi nhận được cảnh báo trên dòng * .delegate = self; nêu rõ: Gán cho id <UIGestureRecognizerDelegate> 'từ loại không tương thích' ViewContoder * const __strong '
David Douglas

2
Kể từ iOS8, câu trả lời được chấp nhận vẫn hoạt động như mong đợi. Có lẽ bạn đang làm sai điều gì đó ..
Alexandre G

Quản lý để làm cho nó bán hoạt động bằng cách gọi câu trả lời được chấp nhận trong viewWillLayoutSubview. Tuy nhiên, việc vuốt đã khiến trang gọi lại 'viewDidLoad' để quay lại câu trả lời của tôi ở trên
Charlie Seligman

@DavidDoumund: có lẽ bạn có thể loại bỏ cảnh báo bằng mã này: __weak __typeof (self) theSafeSelf = self? Sau đó đặt đại biểu cho An toàn.
lifjoy 13/03/2015

1
@DavidDoumund: Bạn cần thêm <UIGestureRecognizerDelegate> vào giao diện để thoát khỏi cảnh báo đó
Primehalo

20

Tôi đã tinh chỉnh câu trả lời của Twan một chút, bởi vì:

  1. bộ điều khiển xem của bạn có thể được đặt làm đại biểu cho các trình nhận dạng cử chỉ khác
  2. đặt đại biểu để nildẫn đến các vấn đề treo khi bạn quay lại trình điều khiển xem gốc và thực hiện cử chỉ vuốt trước khi điều hướng ở nơi khác.

Ví dụ sau giả định 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;
}

+1 "đặt đại biểu thành không dẫn đến sự cố treo khi bạn quay lại trình điều khiển xem gốc và thực hiện thao tác vuốt trước khi điều hướng ở nơi khác."
albertamg

10

Vui lòng đặt cái này trong 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;
}

9

Dành cho Swift:

navigationController!.interactivePopGestureRecognizer!.enabled = false

12
Điều này hoạt động, mặc dù tôi khuyên bạn nên sử dụng chuỗi tùy chọn thay vì buộc mở khóa. ví dụ: self.navlationControll? .interactivePopGestureRecognizer? .isEnables = false
Womble

5

nó hoạt động với tôi trong ios 10 trở lên:

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

}

nó không hoạt động trên phương thức viewDidLoad ().


5

BIÊN TẬP

Nếu bạn muốn quản lý tính năng vuốt ngược cho các bộ điều khiển điều hướng cụ thể, hãy xem xét sử dụng SwipeBack .

Với điều này, bạn có thể thiết lập navigationController.swipeBackEnabled = NO .

Ví dụ:

#import <SwipeBack/SwipeBack.h>

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

Nó có thể được cài đặt thông qua Cốc Cốc .

pod 'SwipeBack', '~> 1.0'

Tôi xin lỗi vì thiếu lời giải thích.


6
Khi quảng cáo một dự án bạn tham gia với bạn phải tiết lộ mối liên kết của bạn với nó.

2
Hơn nữa, mục đích duy nhất của dự án của bạn là kích hoạt thủ công thao tác vuốt khi hệ thống mặc định không hoạt động, trong khi câu hỏi hỏi làm thế nào để vô hiệu hóa cử chỉ toàn hệ thống đó, vì vậy ngay cả khi bạn đặt self.navigationController.swipeBackEnabled = NOtôi chắc chắn điều này sẽ chỉ vô hiệu hóa cử chỉ vuốt ngược của thư viện nhưng hệ thống vẫn sẽ được bật.

1
Xin lỗi vì câu trả lời ngắn gọn của tôi, tôi vừa chỉnh sửa câu trả lời của mình với thông tin bổ sung: "hữu ích cho các bộ điều khiển điều hướng cụ thể". Cảm ơn!
devxoul

Nó xuất hiện để sử dụng swizzle không còn được phép. iOS8?
Matt

1
@devxoul Mình xin lỗi! Tôi nghĩ rằng tôi đã đọc một cái gì đó một thời gian trước nói rằng sưng không còn được phép. Tuy nhiên, tôi không thể tìm thấy bất cứ điều gì nói điều này. Đoán tôi sai.
Matt

4

Phương pháp của tôi. Một nhận dạng cử chỉ để cai trị tất 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)
    }
}

Quan trọng: không đặt lại đại biểu bất cứ nơi nào trong ngăn xếp điều hướng: navigationController!.interactivePopGestureRecognizer!.delegate = nil


3

Đây là cách trên Swift 3

làm việc cho tôi

    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false

3

Tất cả các giải pháp này thao túng nhận dạng cử chỉ của Apple theo cách họ không khuyến nghị. Tôi vừa được một người bạn nói rằng có một giải pháp tốt hơn:

[navigationController.interactivePopGestureRecognizer requireGestureRecognizerToFail: myPanGestureRecognizer];

trong đó myPanGestureRecognizer là trình nhận dạng cử chỉ bạn đang sử dụng để hiển thị menu của mình. Bằng cách đó, trình nhận dạng cử chỉ của Apple sẽ không được bật lại bởi họ khi bạn đẩy bộ điều khiển điều hướng mới và bạn không cần phải dựa vào sự chậm trễ có thể xảy ra quá sớm nếu điện thoại của bạn bị ngủ hoặc quá tải.

Để lại đây vì tôi biết tôi sẽ không nhớ điều này vào lần tới khi tôi cần, và sau đó tôi sẽ có giải pháp cho vấn đề ở đây.


3

swift 5, swift 4.2 có thể sử dụng mã ở bên dưới.

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

2

Không có câu trả lời nào giúp tôi giải quyết vấn đề. Gửi câu trả lời của tôi ở đây; có thể hữu ích cho ai đó

Khai báo private var popGesture: UIGestureRecognizer?là biến toàn cục trong trình điều khiển khung nhìn của bạn. Sau đó triển khai mã trong viewDidAppear các phương thức và 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!)
    }
}

Điều này sẽ vô hiệu hóa vuốt ngược trong iOS v8.x trở đi


Tôi đang cố tưởng tượng trong hoàn cảnh nào điều này sẽ hoạt động, nhưng Jack thì không. Bạn nói rằng bạn đã thử tất cả các câu trả lời khác: điều gì đã sai khi bạn thử Jack?
ToolmakerSteve

Mặt khác, điều này có vẻ đơn giản hơn Jack, nên có lẽ nó không quan trọng. Tôi quyết định như thế này, vì không phải tuyên bố lớp tôi là đại biểu, cũng không phải thao túng interactivePopGestureRecognizer.delegate.
ToolmakerSteve

BTW, mã có thể được đơn giản hóa. Loại bỏ if( .. respondsToSelector ... Dòng tiếp theo đặt popGesture thành một bộ nhận dạng hoặc bằng không. Sau đó sử dụng giá trị của nó : if (self.popGesture != nil) self.navigationController .. removeGestureRecognizer( self.popGesture ).
ToolmakerSteve

2

Điều này hoạt động trong viewDidLoad: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;
  });

Rất nhiều vấn đề có thể được giải quyết với sự giúp đỡ của ol 'tốt dispatch_after .

Mặc dù xin lưu ý rằng giải pháp này có khả năng không an toàn, vui lòng sử dụng lý lẽ của riêng bạn.

Cập nhật

Đối với thời gian trì hoãn iOS 8.1 là 0,5 giây

Trên iOS 9.3 không cần trì hoãn nữa, nó hoạt động chỉ bằng cách đặt cái này vào viewDidLoad:
(TBD nếu hoạt động trên iOS 9.0-9.3)

navigationController?.interactivePopGestureRecognizer?.enabled = false

Trừ khi bạn biết khi trình nhận dạng cử chỉ được cài đặt trên chế độ xem, chờ một khoảng thời gian tùy ý để tắt nó có thể hoặc không thể hoạt động.
kalperin

@kalperin nó không được đảm bảo để hoạt động, mặc dù đôi khi nó là một giải pháp rất tiện dụng. Sử dụng lý luận của riêng bạn.
Dannie P

Nó hoạt động với tôi có phiên bản lớn hơn iOS 8.1 :)
iChirag 16/2/2016

viewDidLoadcộng với sự chậm trễ là một thực hành lập trình rủi ro. Một thói quen xấu để bắt đầu. Điều gì xảy ra nếu người dùng bắt đầu vuốt trước khi cuộc gọi bị trì hoãn của bạn bắt đầu? Không có thời gian an toàn được đảm bảo đủ dài nhưng không quá dài. Đó là lý do tại sao các câu trả lời khác, được đăng rất lâu trước bạn, đề nghị đặt mã vào viewDidAppear. Điều đó đảm bảo rằng mọi thứ được cài đặt. Đừng phát minh sự chậm trễ tùy ý; sử dụng chuỗi cuộc gọi của Apple như dự định.
ToolmakerSteve

1
@iChirag đúng. Tôi đã lưu ý rằng đối với 8.1 bạn cần độ trễ 0,5 giây
Dannie P

1

Đối với Swift 4 , công việc này:

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
    }

}

Bạn không nên ghi đè đại biểu cử chỉ pop tương tác vì nó sẽ gây ra hành vi không có giấy tờ
Josh Bernfeld

Tôi nghĩ rằng nó không thực sự ghi đè đại biểu mà chỉ sửa đổi biến Boolean mà họ đã cung cấp cho mục đích này, vì vậy nó sẽ không thành vấn đề
Lok SN

0

Nó làm việc cho tôi đối với hầu hết những người xem.

self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false

Nó không hoạt động đối với một số trình điều khiển khung nhìn như UIPageViewControll. Trên trình điều khiển pagecontentview điều khiển của UIPageViewControll bên dưới mã làm việc cho tôi.

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
}

Trên UIGestureRecognizerDelegate,

func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
   if gestureRecognizer == self.navigationController?.interactivePopGestureRecognizer {
      return false
}
      return true
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.