วิธีปิดใช้งานท่าทางการปัดย้อนกลับใน UINavigationController บน iOS 7


326

ใน iOS 7 Apple เพิ่มพฤติกรรมการนำทางเริ่มต้นใหม่ คุณสามารถปัดจากขอบซ้ายของหน้าจอเพื่อย้อนกลับไปที่สแต็กการนำทาง แต่ในแอพของฉันพฤติกรรมนี้ขัดแย้งกับเมนูด้านซ้ายที่กำหนดเองของฉัน ดังนั้นจึงเป็นไปได้ที่จะปิดการใช้งานท่าทางใหม่นี้ใน UINavigationController?



2
ฉันก็พบว่าหากคุณตั้งค่าnavigationItem.hidesBackButton = trueท่าทางนี้ก็จะถูกปิดการใช้งาน ในกรณีของฉันฉันใช้ปุ่มย้อนกลับที่กำหนดเองและเพิ่มเป็นleftBarButtonItem
Umair

คำตอบ:


586

ฉันพบวิธีแก้ปัญหา:

Objective-C:

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

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


29
แน่นอนคุณต้องตรวจสอบความพร้อมใช้งานของวิธีการใหม่หากคุณรองรับ iOS เวอร์ชันเก่า
Art Feel

2
มีวิธีการปิดการใช้งานสำหรับมื้อของมุมมองหรือไม่?
Marc

11
คุณสามารถenable / disableจำแนกลายมือบน/viewDidAppear: viewDidDisappearหรือคุณสามารถใช้UIGestureRecognizerDelegateโพรโทคอลด้วยตรรกะที่ซับซ้อนมากขึ้นของคุณและตั้งเป็นrecognizer.delegateคุณสมบัติ
Art รู้สึก

26
เมื่อวันที่ iOS8, การตั้งค่าself.navigationController.interactivePopGestureRecognizer.enabledคุณสมบัติไม่ทำงานในวิธีการดังต่อไปนี้มุมมองของ: viewDidLoad, viewWillAppear, viewDidAppear, แต่ผลงานในวิธีการviewDidDisappear viewWillDisappearบน iOS7 มันทำงานได้ในวิธีการทั้งหมดที่กล่าวมาข้างต้น ดังนั้นลองใช้มันในวิธีอื่นขณะที่ทำงานกับ viewController ฉันยืนยันว่ามันใช้งานได้กับ iOS8 เมื่อฉันคลิกที่ปุ่มด้านใน
Sihad Begovic

8
สามารถยืนยันได้ว่านี่จะไม่ทำงานใน iOS8 ใน viewDidLoad และ viewWillAppear โดยวางไว้ในมุมมองที่เห็นออกมาจากวิดีโอตัวอย่างไม่ได้ใช้เทคนิค
tonytastic

47

ฉันพบว่าการตั้งค่าท่าทางเป็นปิดใช้งานไม่ได้ผลเสมอไป มันใช้งานได้ แต่สำหรับฉันมันทำได้หลังจากที่ฉันเคยใช้แบ็คสโตร์ ครั้งที่สองมันจะไม่ทำให้เกิด backgesture

แก้ไขสำหรับฉันคือการมอบหมายท่าทางและใช้วิธี shouldbegin เพื่อกลับไม่มี:

- (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
ขอบคุณ! จำเป็นต้องปิดการใช้งานการปัดย้อนกลับอย่างสมบูรณ์ มันยังคงมีอยู่ใน iOS 8 และมีกลิ่นเหมือนบั๊กของ Apple
Eric Chen

ขอบคุณดูเหมือนจะเป็นสิ่งเดียวที่ทำงานได้
เบ็น

ฉันไม่รู้ว่าทำไม แต่ตัวควบคุมมุมมองในแอปของฉันด้วยเหตุผลที่ไม่ทราบสาเหตุถูกกระแทกกับท่าทางด้านหลัง .. นี่ช่วยฉันจากการค้นหาเพราะฉันไม่ต้องการท่าทางด้านหลังนี้และฉันจึงปิดการใช้งานรหัสนี้ .. +1
Ahsan Ebrahim

1
@AsanEbrahim เมื่อท่าทางหลังเริ่มขึ้นviewWillAppearจะถูกเรียกใช้ในมุมมองด้านหลังมุมมองปัจจุบัน สิ่งนี้สามารถทำให้เกิดความเสียหายในตรรกะรหัสเนื่องจากมุมมองปัจจุบันยังคงใช้งานอยู่ อาจเป็นสาเหตุของความผิดพลาดของคุณ
phatmann

เป็นenabledYes / No เส้นจำเป็น? คุณกลับมาNOจากที่gestureRecognizerShouldBeginไม่เพียงพอหรือไม่
ToolmakerSteve

30

เพียงลบตัวรู้จำท่าทางออกจาก NavigationController ทำงานใน iOS 8

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

ทางออกเดียวที่ใช้งานได้จริงใน iOS 8 และ 9
Kappe

7
ใช้ได้กับ iOS 10 ด้วยซึ่งควรเป็นคำตอบที่ยอมรับได้ โดยวิธีการถ้าคุณต้องการเปิดใช้งานอีกครั้งทำ[self.navigationController.view addGestureRecognizer:self.navigationController.interactivePopGestureRecognizer]ที่ไหนสักแห่ง
ooops

22

ตั้งแต่ iOS 8 คำตอบที่ยอมรับไม่สามารถใช้งานได้อีกต่อไป ฉันต้องหยุดการปัดเพื่อยกเลิกท่าทางบนหน้าจอเกมหลักของฉันดังนั้นจึงใช้สิ่งนี้:

- (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
ในขณะที่ทำงานกับ iOS8 ฉันได้รับคำเตือนในบรรทัด * .delegate = self; เซน: กำหนดให้ ID <UIGestureRecognizerDelegate> 'จากประเภทที่เข้ากันไม่ได้' ViewController * const __strong '
David Douglas

2
ในฐานะของ iOS8 คำตอบที่ได้รับการยอมรับยังคงทำงานตามที่คาดไว้ คุณอาจทำผิดอย่างอื่นอีก ..
อาเล็กซานเดอร์จี

จัดการเพื่อให้มันทำงานกึ่งโดยการเรียกคำตอบที่ยอมรับใน viewWillLayoutSubviews อย่างไรก็ตามการกวาดทำให้หน้าเรียก 'viewDidLoad' อีกครั้งดังนั้นเปลี่ยนกลับเป็นคำตอบของฉันด้านบน
Charlie Seligman

@DavidDouglas: บางทีคุณสามารถกำจัดคำเตือนด้วยรหัสนี้: __ อ่อนแอ __typeof (ตัวเอง) theSafeSelf = self? จากนั้นตั้งค่าผู้รับมอบสิทธิ์เป็น SafeSelf
lifjoy

1
@DavidDouglas: คุณต้องเพิ่ม <UIGestureRecognizerDelegate> ในอินเทอร์เฟซเพื่อกำจัดคำเตือนนั้น
primehalo

20

ฉันกลั่นกรองคำตอบของ Twan เล็กน้อยเพราะ:

  1. มุมมองตัวควบคุมของคุณอาจถูกตั้งค่าเป็นตัวแทนให้กับตัวจดจำท่าทางอื่น ๆ
  2. การตั้งค่าผู้รับมอบสิทธิ์จะnilนำไปสู่ปัญหาการหยุดเมื่อคุณกลับไปที่ตัวควบคุมรูทมุมมองและทำท่าทางกวาดนิ้วก่อนที่จะไปที่อื่น

ตัวอย่างต่อไปนี้จะถือว่า 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 "การตั้งค่ามอบสิทธิ์ให้เป็นศูนย์จะนำไปสู่ปัญหาการหยุดชะงักเมื่อคุณกลับไปที่ตัวควบคุมรูทมุมมองและทำท่าทางกวาดนิ้วก่อนที่จะไปที่อื่น"
albertamg

10

กรุณาตั้งค่านี้ใน 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

สำหรับ Swift:

navigationController!.interactivePopGestureRecognizer!.enabled = false

12
ใช้งานได้แม้ว่าฉันจะแนะนำให้ใช้การผูกมัดตัวเลือกแทนการบังคับให้เปิดออก เช่น self.navigationController? .interactivePopGestureRecognizer? .isEnabled = false
Womble

5

มันเหมาะกับฉันใน iOS 10 และใหม่กว่า:

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

}

มันไม่ทำงานในวิธีการ viewDidLoad ()


5

แก้ไข

หากคุณต้องการจัดการคุณลักษณะกลับรูดสำหรับตัวควบคุมการนำทางที่เฉพาะเจาะจงให้พิจารณาใช้SwipeBack

navigationController.swipeBackEnabled = NOด้วยวิธีนี้คุณสามารถตั้งค่า

ตัวอย่างเช่น:

#import <SwipeBack/SwipeBack.h>

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

มันสามารถติดตั้งผ่านทางCocoaPods

pod 'SwipeBack', '~> 1.0'

ฉันขอโทษที่ไม่มีคำอธิบาย


6
เมื่อโปรโมตโครงการที่คุณมีส่วนเกี่ยวข้องคุณต้องเปิดเผยความร่วมมือของคุณด้วย

2
ยิ่งกว่านั้นจุดประสงค์เดียวของโครงการของคุณคือการเปิดใช้งานการเลื่อนนิ้วด้วยตนเองเมื่อระบบเริ่มต้นไม่ทำงานในขณะที่คำถามถามว่าจะปิดการใช้งานท่าทางกว้างของระบบนั้นได้อย่างไรแม้ว่าคุณจะตั้งค่าself.navigationController.swipeBackEnabled = NOแล้วฉันค่อนข้างแน่ใจว่า รูปแบบการปัดกลับของไลบรารี แต่ระบบยังคงเปิดใช้งานอยู่

1
ขออภัยสำหรับคำตอบสั้น ๆ ฉันเพิ่งแก้ไขคำตอบด้วยข้อมูลเพิ่มเติม: "มีประโยชน์สำหรับตัวควบคุมการนำทางเฉพาะ" ขอบคุณ!
devxoul

ดูเหมือนว่าจะใช้ Swizzle ซึ่งไม่ได้รับอนุญาตอีกต่อไป iOS8?
แมตต์

1
@devxoul ฉันขอโทษ! ฉันคิดว่าฉันได้อ่านบางอย่างมานานแล้วโดยบอกว่าไม่อนุญาตให้มีการมั่ว อย่างไรก็ตามฉันไม่พบสิ่งใดที่พูดสิ่งนี้ คิดว่าฉันผิด
แมตต์

4

วิธีการของฉัน ตัวจดจำท่าทางสัมผัสหนึ่งกฎเพื่อควบคุมทั้งหมด:

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

สำคัญ: อย่ารีเซ็ตผู้รับมอบสิทธิ์ที่ใดก็ได้ในสแต็กการนำทาง navigationController!.interactivePopGestureRecognizer!.delegate = nil


3

นี่คือวิธีใน Swift 3

ทำงานได้สำหรับฉัน

    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false

3

โซลูชันทั้งหมดเหล่านี้ใช้กับเครื่องจดจำท่าทางของ Apple ในแบบที่ไม่แนะนำ ฉันเพิ่งได้รับการบอกเล่าจากเพื่อนว่ามีวิธีแก้ไขที่ดีกว่า:

[navigationController.interactivePopGestureRecognizer requireGestureRecognizerToFail: myPanGestureRecognizer];

โดยที่ myPanGestureRecognizer เป็นตัวจดจำท่าทางที่คุณใช้เช่นแสดงเมนูของคุณ ด้วยวิธีการดังกล่าวตัวจดจำท่าทางของ Apple จะไม่ถูกเปิดใช้งานโดยพวกเขาเมื่อคุณกดตัวควบคุมการนำทางใหม่และคุณไม่จำเป็นต้องพึ่งพาความล่าช้าของแฮ็กที่อาจเริ่มเร็วเกินไปหากโทรศัพท์ของคุณเข้าสู่โหมดสลีป

ออกจากที่นี่เพราะฉันรู้ว่าฉันจะจำไม่ได้ในครั้งต่อไปที่ฉันต้องการมันแล้วฉันจะแก้ปัญหาที่นี่


3

swift 5, swift 4.2 สามารถใช้รหัสได้ด้านล่าง

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

2

ไม่มีคำตอบใดที่ช่วยฉันแก้ไขปัญหาได้ โพสต์คำตอบของฉันที่นี่; อาจเป็นประโยชน์สำหรับใครบางคน

ประกาศprivate var popGesture: UIGestureRecognizer?เป็นตัวแปรโกลบอลใน viewcontroller ของคุณ แล้วใช้รหัสในการviewDidAppearและ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!)
    }
}

การดำเนินการนี้จะปิดใช้งานการกวาดนิ้วใน iOS v8.xเป็นต้นไป


ฉันพยายามจินตนาการภายใต้สถานการณ์ที่สิ่งนี้จะทำงานได้ แต่แจ็คจะไม่ คุณบอกว่าคุณลองคำตอบอื่น ๆ ทั้งหมด: มีอะไรผิดพลาดเมื่อคุณลองแจ็ค?
ToolmakerSteve

ในทางกลับกันสิ่งนี้ดูง่ายกว่าของแจ็คดังนั้นมันอาจไม่สำคัญ interactivePopGestureRecognizer.delegateฉันตัดสินใจเช่นนี้เพราะไม่ได้มีการประกาศระดับของฉันเป็นตัวแทนหรือจัดการ
ToolmakerSteve

BTW รหัสสามารถลดความซับซ้อน if( .. respondsToSelector ..ลบ บรรทัดถัดไปตั้งค่า popGesture ให้กับตัวจดจำหรือเป็นศูนย์ จากนั้นใช้ค่าของมัน: if (self.popGesture != nil) self.navigationController .. removeGestureRecognizer( self.popGesture ).
ToolmakerSteve

2

ใช้งานได้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;
  });

จำนวนมากของปัญหาที่สามารถแก้ไขได้ด้วยความช่วยเหลือของดี dispatch_afterol'

แม้ว่าโปรดทราบว่าวิธีนี้อาจไม่ปลอดภัยโปรดใช้เหตุผลของคุณเอง

ปรับปรุง

สำหรับ iOS 8.1 การหน่วงเวลาควรเป็น 0.5 วินาที

บน iOS 9.3 ไม่จำเป็นต้องรออีกต่อไปมันใช้งานได้เพียงแค่วางลงในviewDidLoad:
(TBD ถ้าใช้ได้กับ iOS 9.0-9.3)

navigationController?.interactivePopGestureRecognizer?.enabled = false

หากคุณไม่ทราบว่าเมื่อติดตั้งตัวจำแนกท่าทางบนมุมมองแล้วให้รอเวลาในการปิดใช้งานตามอำเภอใจหรืออาจไม่ทำงาน
kalperin

@kalperin ไม่รับประกันว่าจะใช้งานได้แม้จะเป็นวิธีแก้ปัญหาที่สะดวกมากในบางครั้ง ใช้เหตุผลของคุณเอง
Dannie P

มันใช้งานได้สำหรับฉันที่มีเวอร์ชันมากกว่า iOS 8.1 :)
iChirag

viewDidLoadบวกความล่าช้าคือการปฏิบัติการเขียนโปรแกรมที่มีความเสี่ยง นิสัยที่ไม่ดีในการเริ่มต้น เกิดอะไรขึ้นถ้าผู้ใช้เริ่มต้นการปัดก่อนที่การโทรที่ล่าช้าของคุณจะเริ่มขึ้น ไม่มีเวลาปลอดภัยที่รับประกันว่าจะยาวพอ แต่ไม่นานเกินไป นั่นคือเหตุผลที่คำตอบอื่น ๆ viewDidAppearโพสต์นานก่อนที่จะแสดงความนับถือขอแนะนำให้วางโค้ดใน รับรองว่าติดตั้งทุกอย่างแล้ว อย่าประดิษฐ์ความล่าช้าโดยพลการ ใช้ลำดับการโทรของ Apple ตามที่ตั้งใจไว้
ToolmakerSteve

1
@iChirag จริง ฉันได้สังเกตว่าสำหรับ 8.1 คุณต้องหน่วงเวลา 0.5 วินาที
Dannie P

1

สำหรับSwift 4การทำงานนี้:

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
    }

}

คุณไม่ควรแทนที่ผู้แทนที่ท่าทางป๊อปอินเทอร์แอคทีฟเนื่องจากจะทำให้เกิดพฤติกรรมที่ไม่มีเอกสาร
Josh Bernfeld

ฉันคิดว่ามันไม่ได้แทนที่ผู้ได้รับมอบหมาย แต่เพียงปรับเปลี่ยนตัวแปรบูลีนที่พวกเขาได้จัดทำขึ้นเพื่อจุดประสงค์นี้ดังนั้นมันจะไม่เกิดปัญหา
Lok SN

0

มันใช้งานได้กับฉันสำหรับผู้ดูส่วนใหญ่

self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false

มันไม่ทำงานสำหรับผู้ควบคุมบางคนเช่น UIPageViewController pagecontentviewcontroller ของ UIPageViewController ด้านล่างรหัสทำงานให้ฉัน

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

func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
   if gestureRecognizer == self.navigationController?.interactivePopGestureRecognizer {
      return false
}
      return true
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.