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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19054625/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 01:47:07  来源:igfitidea点击:

Changing back button in iOS 7 disables swipe to navigate back

iosuinavigationcontrollerios7uibarbuttonitemuiviewanimation

提问by lehn0058

I have an iOS 7 app where I am setting a custom back button like this:

我有一个 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;

But this disables the iOS 7 "swipe left to right" gesture to navigate to the previous controller. Does anyone know how I can set a custom button and still keep this gesture enabled?

但这会禁用 iOS 7“从左向右滑动”手势以导航到上一个控制器。有谁知道如何设置自定义按钮并仍然启用此手势?

EDIT: I tried to set the viewController.navigationItem.backBarButtonItem instead, but this doesn't seem to show my custom image.

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

采纳答案by Paul Hunter

IMPORTANT:This is a hack. I would recommend taking a look at this answer.

重要提示:这是一个黑客。我建议看看这个答案

Calling the following line after assigning the leftBarButtonItemworked for me:

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

self.navigationController.interactivePopGestureRecognizer.delegate = self;

Edit:This does not work if called in initmethods. It should be called in viewDidLoador similar methods.

编辑:如果在init方法中调用,这不起作用。它应该在viewDidLoad或类似的方法中调用。

回答by Saltymule

Use the backIndicatorImage and backIndicatorTransitionMaskImage properties of the UINavigationBar if at all possible. Setting these on an a UIAppearanceProxy can easily modify behavior across your application. The wrinkle is that you can only set those on ios 7, but that works out because you can only use the pop gesture on ios 7 anyway. Your normal ios 6 styling can remain intact.

如果可能,请使用 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
}

Trying to manipulate the interactivePopGestureRecognizer's delegate will lead to a lot of issues.

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

回答by Nick H247

I saw this solution http://keighl.com/post/ios7-interactive-pop-gesture-custom-back-button/which subclasses UINavigationController. Its a better solution as it handles the case where you swipe before the controller is in place - which causes a crash.

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

In addition to this I noticed if you do a swipe on the root view controller (after pushing on one, and back again) the UI becomes unresponsive (also same problem in answer above).

除此之外,我注意到如果您在根视图控制器上滑动(按下一个,然后再次返回),UI 会变得无响应(上面的答案也是同样的问题)。

So the code in the subclassed UINavigationController should look like so:

所以子类 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 {
    // HiHyman 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

回答by Albert Chu

I use

我用

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

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

回答by duan

Here is swift3 version of Nick H247's answer

这是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 {}

回答by Mr. Ming

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

This is from http://stuartkhall.com/posts/ios-7-development-tips-tricks-hacks, but it causes several bugs:

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

  1. Push another viewController into the navigationController when swiping in from the left edge of the screen;
  2. Or, swipe in from the left edge of the screen when the topViewController is popping up from the navigationController;
  1. 从屏幕左边缘滑入时,将另一个 viewController 推入 navigationController 中;
  2. 或者,当 topViewController 从导航控制器弹出时,从屏幕的左边缘滑入;

e.g. When the rootViewController of navigationController is showing, swipe in from the left edge of the screen, and tap something(QUICKLY) to push anotherViewController into the navigationController, then

例如,当navigationController 的rootViewController 显示时,从屏幕左边缘向内滑动,然后点击某物(快速)将anotherViewController 推入navigationController,然后

  • The rootViewController does not respond any touch event;
  • The anotherViewController will not be shown;
  • Swipe from the edge of the screen again, the anotherViewController will be shown;
  • Tap the custom back button to pop the anotherViewController, crash!
  • rootViewController 不响应任何触摸事件;
  • anotherViewController 将不会显示;
  • 再次从屏幕边缘滑动,显示 anotherViewController;
  • 点击自定义后退按钮弹出anotherViewController,崩溃!

So you must implement UIGestureRecognizerDelegatemethod in self.navigationController.interactivePopGestureRecognizer.delegatelike this:

所以你必须像这样实现UIGestureRecognizerDelegate方法self.navigationController.interactivePopGestureRecognizer.delegate

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

回答by avishic

I also hide the back button, replacing it with a custom leftBarItem.
Removing interactivePopGestureRecognizer delegate after push action worked for me:

我还隐藏了后退按钮,用自定义的 leftBarItem 替换它。
推送操作后删除交互PopGestureRecognizer委托对我有用:

[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;
}

回答by ilya n.

Try self.navigationController.interactivePopGestureRecognizer.enabled = YES;

尝试 self.navigationController.interactivePopGestureRecognizer.enabled = YES;

回答by PW486

RootView

根视图

override func viewDidAppear(_ animated: Bool) {
    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
}

ChildView

子视图

override func viewDidLoad() {
    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true
    self.navigationController?.interactivePopGestureRecognizer?.delegate = self
} 

extension ChildViewController: UIGestureRecognizerDelegate {}

回答by Muhammad Naeem Paracha

Use this logic to keep enable or disable the swipe gesture..

使用此逻辑来保持启用或禁用滑动手势..

- (void)navigationController:(UINavigationController *)navigationController
       didShowViewController:(UIViewController *)viewController
                    animated:(BOOL)animate
{
    if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])
    {
        if (self.navigationController.viewControllers.count > 1)
        {
            self.navigationController.interactivePopGestureRecognizer.enabled = YES;
        }
        else
        {
            self.navigationController.interactivePopGestureRecognizer.enabled = NO;
        }
    }
}