在iOS 7中更改后退按钮会禁用滑动以返回导航

leh*_*058 79 uinavigationcontroller uibarbuttonitem uiviewanimation ios ios7

我有一个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;
Run Code Online (Sandbox Code Playgroud)

但是这会禁用iOS 7"从左向右滑动"手势以导航到之前的控制器.有谁知道如何设置自定义按钮并仍然启用此手势?

编辑:我试图设置viewController.navigationItem.backBarButtonItem,但这似乎并没有显示我的自定义图像.

Pau*_*ter 78

重要提示: 这是一个黑客攻击.我建议你看看这个答案.

leftBarButtonItem在为我分配工作后调用以下行:

self.navigationController.interactivePopGestureRecognizer.delegate = self;
Run Code Online (Sandbox Code Playgroud)

编辑: 如果在init方法中调用,则不起作用.它应该被称为viewDidLoad或类似的方法.

  • 我有这个代码的问题.它工作不是很长时间,经过5-10次背刷VC冻结.有解决方案吗 (8认同)
  • 将委托设置为`self`会将其从类_UINavigationInteractiveTransition`的对象中取消.该对象的责任是确保导航控制器在转换过程中不被告知弹出.当后退按钮是自定义时,仍在调查是否可以启用此手势. (4认同)

Sal*_*ule 56

如果可能的话,使用UINavigationBar的backIndicatorImage和backIndicatorTransitionMaskImage属性.在UIAppearanceProxy上设置这些可以轻松修改整个应用程序的行为.皱纹是你只能在ios 7上设置它们,但这样才能解决,因为你无论如何都只能在ios 7上使用pop手势.您的正常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
}
Run Code Online (Sandbox Code Playgroud)

试图操纵interactivePopGestureRecognizer的委托会导致很多问题.

  • 谢谢Dan,这非常重要,应该是公认的答案.通过简单地重新分配代表,你可以打开很多奇怪的行为.特别是当用户试图刷回`topViewController`时. (4认同)
  • 不幸的是,这在iOS8上不起作用.后退按钮不会将其外观更改为我的自定义图像. (2认同)

Nic*_*247 29

我看到了这个解决方案http://keighl.com/post/ios7-interactive-pop-gesture-custom-back-button/,它是UINavigationController的子类.它是一个更好的解决方案,因为它处理在控制器到位之前滑动的情况 - 这会导致崩溃.

除此之外,我注意到如果你在根视图控制器上进行滑动(在按下一个后再返回),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
Run Code Online (Sandbox Code Playgroud)


Alb*_*Chu 19

我用

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

[UIBarButtonItem.appearance setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -64) forBarMetrics:UIBarMetricsDefault];
Run Code Online (Sandbox Code Playgroud)

  • 我在其他地方看到过这样的评论,由于目前Apple的代码中存在错误,导致64位模式出现问题 - 我以为我会发布警告 (2认同)

avi*_*hic 6

我还隐藏了后退按钮,将其替换为自定义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;
}
Run Code Online (Sandbox Code Playgroud)

  • 此方法的一个问题是,如果在根视图上执行边缘平移,它将锁定UI.我遇到了这个,因为我正在将相同视图的多个实例推送到导航堆栈. (4认同)
  • 我在viewDidLoad方法中设置它.我的最终解决方案是将另一个类设置为委托,如果导航堆栈中有多个视图控制器,则只为'gestureRecognizerShouldBegin'返回true. (4认同)

iwi*_*ill 6

navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
Run Code Online (Sandbox Code Playgroud)

这是来自http://stuartkhall.com/posts/ios-7-development-tips-tricks-hacks,但它会导致一些错误:

  1. 从屏幕左边缘扫入时,将另一个viewController推入navigationController;
  2. 或者,当从navigationController弹出topViewController时,从屏幕左边缘滑入;

例如,当navigationController的rootViewController显示时,从屏幕的左边缘扫入,然后点击一些东西(QUICKLY)将另一个ViewController推入navigationController,然后

  • rootViewController不响应任何触摸事件;
  • 另一个ViewController将不会显示;
  • 再次从屏幕边缘滑动,将显示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;
}
Run Code Online (Sandbox Code Playgroud)


dua*_*uan 6

这是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 {}
Run Code Online (Sandbox Code Playgroud)