iOS 7의 UINavigationController에서 뒤로 스 와이프 동작을 비활성화하는 방법


326

iOS 7에서 Apple은 새로운 기본 탐색 동작을 추가했습니다. 화면 왼쪽 가장자리에서 스 와이프하여 탐색 스택으로 돌아갈 수 있습니다. 그러나 내 앱 에서이 동작은 내 사용자 정의 왼쪽 메뉴와 충돌합니다. UINavigationController에서이 새로운 제스처를 비활성화 할 수 있습니까?



2
또한 설정 navigationItem.hidesBackButton = true하면이 동작도 비활성화됩니다. 내 경우에는 내가 정의의 뒤로 버튼을 구현하고로 추가leftBarButtonItem
UMAIR

답변:


586

해결책을 찾았습니다.

목표 -C :

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

스위프트 3+ :
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false


29
물론 이전 버전의 iOS를 지원하는 경우 새로운 방법의 가용성을 확인해야합니다.
ArtFeel

2
보기의 일부로 사용하지 않도록 설정하는 방법이 있습니까?
Marc

11
/에서 enable / disable인식기를 사용할 수 있습니다 . 또는 더 복잡한 로직으로 프로토콜을 구현 하고 속성으로 설정할 수 있습니다. viewDidAppear:viewDidDisappearUIGestureRecognizerDelegaterecognizer.delegate
ArtFeel

26
iOS8의에서 설정 self.navigationController.interactivePopGestureRecognizer.enabled프로퍼티하는 뷰의 방법을 다음에서 작동하지 않습니다 : viewDidLoad, viewWillAppear, viewDidAppear, viewDidDisappear,하지만 방법 작품 viewWillDisappear. iOS7에서는 위에서 언급 한 모든 방법으로 작동합니다. 따라서 viewController에서 작업하는 동안 다른 방법으로 사용하려고하면보기 내부의 일부 버튼을 클릭하면 iOS8에서 작동한다는 것을 확인합니다.
Sihad Begovic

8
이 viewwilllayoutgubviews에 트릭을 않았다 가하고있는 viewDidLoad 및 viewWillAppear에서 iOS8의에서 작동하지 않습니다 확인 할 수
tonytastic

47

제스처를 비활성화로 설정하는 것이 항상 작동하지는 않는다는 것을 알았습니다. 그것은 효과가 있지만, 한 번은 backgesture를 사용한 후에 만되었습니다. 두 번째로 백 제스처를 트리거하지 않습니다.

나를 위해 수정은 제스처를 위임하고 NO를 반환하도록 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

고맙습니다, 일한 유일한 것 같습니다.
Ben

나는 왜 알지 못하지만 알 수없는 이유로 내 응용 프로그램의 뷰 컨트롤러 가이 백 제스처에서 충돌하고 있습니다.이 백 제스처가 필요하지
않아서이

1
뒤로 동작이 시작되면 @AhsanEbrahim viewWillAppear이 현재보기 뒤의보기에서 호출됩니다. 현재보기가 여전히 활성 상태이므로 코드 논리가 혼란 스러울 수 있습니다. 충돌의 원인이 될 수 있습니다.
phatmann

있습니까 enabled예는 / 더 선은 필요하지? 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; 진술 : 호환되지 않는 유형 'ViewController * const __strong'에서 id <UIGestureRecognizerDelegate> '에 할당
David Douglas

2
iOS8부터 수락 된 답변은 여전히 ​​예상대로 작동합니다. 당신은 아마 다른 무언가를하고있을 것입니다 ..
Alexandre G

viewWillLayoutSubviews에서 허용 된 답변을 호출하여 반 작동하도록했습니다. 그러나, 스 와이프 다시 그래서 위의 내 대답에 다시 복귀 콜 '의 viewDidLoad'에 페이지 원인 한
찰리 셀리그

@DavidDouglas : 아마도이 코드로 경고를 제거 할 수 있습니다 : __weak __typeof (self) 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 "대리자를 nil로 설정하면 루트 뷰 컨트롤러로 돌아가서 다른 곳으로 이동하기 전에 스 와이프 제스처를 만들 때 정지 문제가 발생합니다."
albertamg

10

루트 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

스위프트

navigationController!.interactivePopGestureRecognizer!.enabled = false

12
강제 언 래핑 대신 선택적 체인을 사용하는 것이 좋습니다. 예 : self.navigationController? .interactivePopGestureRecognizer? .isEnabled = false
17

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

더 이상 허용되지 않는 스위 즐을 사용하는 것 같습니다. iOS8?
Matt

1
@devxoul 죄송합니다! 나는 더 이상 지글 지글이 더 이상 허용되지 않는다고 말하는 것을 읽었다 고 생각했다. 그러나 나는 이것을 말하는 것을 찾을 수 없습니다. 내가 틀린 것 같아
Matt

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

이것은 스위프트 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?뷰 컨트롤러에서 전역 변수로 선언 하십시오. 그런 다음 viewDidAppearviewWillDisappear 메소드 에서 코드를 구현하십시오.

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 부터 다시 스 와이프하지 않습니다.


어떤 상황에서 이것이 효과가 있을지 상상하려고 노력하고 있지만 Jack은 그렇지 않습니다. 당신은 당신이 다른 모든 대답을 시도했다고 말합니다 : 당신이 잭을 시도했을 때 무엇이 ​​잘못 되었습니까?
ToolmakerSteve

반면에, 이것은 Jack 's보다 단순 해 보이므로 중요하지 않을 수 있습니다. 클래스를 대리자로 선언하거나 조작 할 필요가 없기 때문에 이것을 좋아하기로 결정했습니다 interactivePopGestureRecognizer.delegate.
ToolmakerSteve

BTW, 코드를 단순화 할 수 있습니다. 를 제거하십시오 if( .. respondsToSelector ... 다음 줄은 popGesture를 인식기 또는 nil로 설정합니다. 그런 다음 값을 사용하십시오 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_after.

이 솔루션은 잠재적으로 안전하지 않지만 자체 추론을 사용하십시오.

최신 정보

iOS 8.1의 경우 지연 시간은 0.5 초 여야합니다.

iOS 9.3에서는 더 이상 지연이 필요하지 않습니다. 다음에 배치하면됩니다 viewDidLoad.
(iOS 9.0-9.3에서 작동하는 경우 TBD)

navigationController?.interactivePopGestureRecognizer?.enabled = false

제스처 인식기가 뷰에 설치되어있는 시점을 알지 못하면 임의의 시간 동안 기다렸다가 작동하지 않을 수 있습니다.
kalperin

@kalperin 작동이 보장되지는 않지만 때로는 매우 편리한 솔루션입니다. 자신의 추론을 사용하십시오.
Dannie P

그것은 iOS 8.1보다 큰 버전을 가지고 나를 위해 일했습니다 :)
iChirag

viewDidLoad플러스 지연은 위험한 프로그래밍 관행입니다. 시작하는 나쁜 습관. 지연된 통화가 시작되기 전에 사용자가 스 와이프를 시작하면 어떻게 되나요? 충분히 길지만 너무 길지 않은 안전한 시간은 없습니다. 그래서 오래 전에 게시 된 다른 답변이 코드를에 배치하는 것이 좋습니다 viewDidAppear. 그러면 모든 것이 설치됩니다. 임의의 지연을 만들지 마십시오. 의도 한대로 Apple의 일련의 통화를 사용하십시오.
ToolmakerSteve

1
@iChirag true입니다. 8.1의 경우 0.5 초 지연이 필요합니다.
Dannie P

1

들어 스위프트 넷 이 작동합니다 :

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와 같은 일부 뷰 컨트롤러에서는 작동하지 않았습니다. UIPageViewController의 pagecontentviewcontroller 아래 코드가 저에게 효과적이었습니다.

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.