[ios] iOS 7에서 뒤로 버튼을 변경하면 뒤로 이동하려면 스 와이프가 비활성화됩니다.

다음과 같은 사용자 지정 뒤로 버튼을 설정하는 iOS 7 앱이 있습니다.

    UIImage *backButtonImage = [UIImage imageNamed:@"back-button"];
    UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];

    [backButton setImage:backButtonImage forState:UIControlStateNormal];
    backButton.frame = CGRectMake(0, 0, 20, 20);

    [backButton addTarget:self
                   action:@selector(popViewController)
         forControlEvents:UIControlEventTouchUpInside];

    UIBarButtonItem *backBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
    viewController.navigationItem.leftBarButtonItem = backBarButtonItem;

그러나 이렇게하면 iOS 7 “왼쪽에서 오른쪽으로 스 와이프”동작이 비활성화되어 이전 컨트롤러로 이동합니다. 사용자 정의 버튼을 설정하고이 제스처를 계속 활성화 할 수있는 방법을 아는 사람이 있습니까?

편집 : 대신 viewController.navigationItem.backBarButtonItem을 설정하려고했지만 내 사용자 지정 이미지가 표시되지 않는 것 같습니다.



답변

중요 :
이것은 해킹입니다. 이 답변을 살펴 보는 것이 좋습니다 .

leftBarButtonItem나를 위해 일한 것을 할당 한 후 다음 라인을 호출하십시오 .

self.navigationController.interactivePopGestureRecognizer.delegate = self;

편집 :init 메서드
에서 호출하면 작동하지 않습니다 . in viewDidLoad또는 유사한 메서드를 호출해야합니다 .


답변

가능한 경우 UINavigationBar의 backIndicatorImage 및 backIndicatorTransitionMaskImage 속성을 사용합니다. UIAppearanceProxy에서이를 설정하면 애플리케이션에서 동작을 쉽게 수정할 수 있습니다. 주름은 ios 7에서만 설정할 수 있지만 어쨌든 ios 7에서만 팝 제스처를 사용할 수 있기 때문에 효과가 있습니다. 일반적인 iOS 6 스타일은 그대로 유지할 수 있습니다.

UINavigationBar* appearanceNavigationBar = [UINavigationBar appearance];
//the appearanceProxy returns NO, so ask the class directly
if ([[UINavigationBar class] instancesRespondToSelector:@selector(setBackIndicatorImage:)])
{
    appearanceNavigationBar.backIndicatorImage = [UIImage imageNamed:@"back"];
    appearanceNavigationBar.backIndicatorTransitionMaskImage = [UIImage imageNamed:@"back"];
    //sets back button color
    appearanceNavigationBar.tintColor = [UIColor whiteColor];
}else{
    //do ios 6 customization
}

interactivePopGestureRecognizer의 델리게이트를 조작하려고하면 많은 문제가 발생합니다.


답변

UINavigationController를 하위 클래스로 만드는 이 솔루션 http://keighl.com/post/ios7-interactive-pop-gesture-custom-back-button/ 을 보았습니다 . 컨트롤러가 제자리에 놓이기 전에 스 와이프하는 경우를 처리하므로 더 나은 솔루션으로 충돌이 발생합니다.

이 외에도 루트 뷰 컨트롤러에서 스 와이프를 수행하면 (하나를 누른 후 다시 뒤로) UI가 응답하지 않는 것으로 나타났습니다 (위의 답변에서도 동일한 문제).

따라서 서브 클래 싱 된 UINavigationController의 코드는 다음과 같아야합니다.

@implementation NavigationController

- (void)viewDidLoad {
    [super viewDidLoad];
    __weak NavigationController *weakSelf = self;

    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.interactivePopGestureRecognizer.delegate = weakSelf;
        self.delegate = weakSelf;
    }
}

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
    // Hijack the push method to disable the gesture
    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.interactivePopGestureRecognizer.enabled = NO;
    }
    [super pushViewController:viewController animated:animated];
}

#pragma mark - UINavigationControllerDelegate

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animate {
    // Enable the gesture again once the new controller is shown
    self.interactivePopGestureRecognizer.enabled = ([self respondsToSelector:@selector(interactivePopGestureRecognizer)] && [self.viewControllers count] > 1);
}

@end


답변

나는 사용한다

[[UINavigationBar appearance] setBackIndicatorImage:[UIImage imageNamed:@"nav_back.png"]];
[[UINavigationBar appearance] setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"nav_back.png"]];

[UIBarButtonItem.appearance setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -64) forBarMetrics:UIBarMetricsDefault];


답변

또한 뒤로 버튼을 숨기고 사용자 정의 leftBarItem으로 바꿉니다.
푸시 작업 후 interactivePopGestureRecognizer 대리자를 제거하면 나를 위해 일했습니다.

[self.navigationController pushViewController:vcToPush animated:YES];

// Enabling iOS 7 screen-edge-pan-gesture for pop action
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
    self.navigationController.interactivePopGestureRecognizer.delegate = nil;
}


답변

navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;

이것은 http://stuartkhall.com/posts/ios-7-development-tips-tricks-hacks 에서 왔지만 몇 가지 버그가 발생합니다.

  1. 화면의 왼쪽 가장자리에서 스 와이프 할 때 다른 viewController를 navigationController에 밀어 넣습니다.
  2. 또는 topViewController가 navigationController에서 팝업 될 때 화면의 왼쪽 가장자리에서 안으로 스 와이프합니다.

예를 들어 navigationController의 rootViewController가 표시되면 화면 왼쪽 가장자리에서 안쪽으로 스 와이프하고 무언가를 탭 (빠르게)하여 다른 ViewController를 navigationController로 푸시 한 다음

  • rootViewController는 터치 이벤트에 응답하지 않습니다.
  • anotherViewController는 표시되지 않습니다.
  • 화면 가장자리에서 다시 스 와이프하면 anotherViewController가 표시됩니다.
  • 사용자 정의 뒤로 버튼을 탭하여 anotherViewController를 팝업하고 충돌합니다!

따라서 다음 과 같이 UIGestureRecognizerDelegate메소드를 구현해야합니다 self.navigationController.interactivePopGestureRecognizer.delegate.

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    if (gestureRecognizer == navigationController.interactivePopGestureRecognizer) {
        return !navigationController.<#TODO: isPushAnimating#> && [navigationController.viewControllers count] > 1;
    }
    return YES;
}


답변

다음은 Nick H247의 답변의 swift3 버전입니다.

class NavigationController: UINavigationController {
  override func viewDidLoad() {
    super.viewDidLoad()
    if responds(to: #selector(getter: interactivePopGestureRecognizer)) {
      interactivePopGestureRecognizer?.delegate = self
      delegate = self
    }
  }

  override func pushViewController(_ viewController: UIViewController, animated: Bool) {
    if responds(to: #selector(getter: interactivePopGestureRecognizer)) {
      interactivePopGestureRecognizer?.isEnabled = false
    }
    super.pushViewController(viewController, animated: animated)
  }
}

extension NavigationController: UINavigationControllerDelegate {
  func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
    interactivePopGestureRecognizer?.isEnabled = (responds(to: #selector(getter: interactivePopGestureRecognizer)) && viewControllers.count > 1)
  }
}

extension NavigationController: UIGestureRecognizerDelegate {}