iOS 7 返回按钮弹出手势

16

iOS 7中新增了向右滑动手势来返回上一个UIViewController,在屏幕左侧从左往右滑动即可触发UINavigationController的返回操作。

但是如果我像这样创建自定义的返回按钮,那么向右滑动手势将不再起作用:

UIBarButtonItem *customBackButton = [[UIBarButtonItem alloc] initWithTitle:@" " style:UIBarButtonItemStyleBordered target:self action:@selector(navigateBack)];
[customBackButton setBackButtonBackgroundImage:barBackBtnImg forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[customBackButton setBackButtonBackgroundImage:barBackBtnImgHighlighted forBarMetrics:UIBarMetricsDefault];
self.navigationItem.backBarButtonItem = customBackButton;

我该如何使用自定义返回按钮并且保留原生的滑动手势来进行页面返回?

更新:

这是在navigateBack中发生的事情:

- (void)navigateBack {
    [self.navigationController popViewControllerAnimated:YES];
}

你可以使用外观代理来自定义返回按钮图像吗? - Robert
7个回答

35

不需要添加自己的手势识别。UINavigationController已经为您完成了这一步骤。

在启用它之前,需要为interactivePopGestureRecognizer设置委托。

请执行以下两个操作:

self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
[self.navigationController.interactivePopGestureRecognizer setEnabled:YES];

1
这应该是正确的答案。我刚刚通过创建自定义转换并手动操作我的UIScreenEdgePanGestureRecognizer来操纵弹出过程。在这里看到了你的答案,就说,试一试吧。只需两行代码,完美运行。 - Dean Davids
2
我发现,如果你在 UINavigationController 转场期间开始进行后退手势,这可能会导致一些非常奇怪的行为。例如,如果我点击一个按钮将一个新控制器推入 UINavigationController 的堆栈,并立即向后滑动,我会陷入一个中间状态,其中导航栏显示为我在第一个屏幕(推入,然后弹出),但导航控制器的内容显示为第二个屏幕,就好像弹出从未发生过一样。我现在正在使用码农白腩肚提出的解决方案,但那仍然有点像是一个 hack。 - jsadler
是的,我自己也见证了这种行为。如果您正在使用带有UINavigationBar的UINavigationController,则无需使用此代码片段。导航栏会自行处理它,并且您不会被困在中间状态。 - udit gupta
如果你的navigationBar被隐藏了,这个方法同样适用。谢谢! - Markus
谢谢!节省了很多时间。 - Dmitriy Kalachniuk

13

只需添加以下一行代码:

[self.navigationController.interactivePopGestureRecognizer addTarget:self action:@selector(handleGesture:)];

您可以添加自己的 UIGestureRecognizer 并自行弹出 UIViewController。请参阅文档了解更多信息。


3
尝试了那种方式,但动作没有被调用,不过我使用了自定义的返回按钮。在使用标准返回按钮时,该动作被调用。 - hsafarya

3

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];

2
为了避免崩溃,您需要小心地添加和删除自定义的返回选择器。原因是当您推送弹出控制器时,导航控制器仍然存在。 如已经说明的,在添加自定义返回按钮+选择器后,您应该在viewDidAppear中执行以下操作。
    if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])
    {
       self.navigationController.interactivePopGestureRecognizer.enabled = YES;
       self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
       [self.navigationController.interactivePopGestureRecognizer addTarget:self action:@selector(navigateBack)];
    }

然后在 viewWillDisapear 中执行以下操作:

        if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])
        {
           [self.navigationController.interactivePopGestureRecognizer removeTarget:self action:@selector(performCompletion)];
        }

这些调用的时机至关重要。否则,你可能会遇到崩溃问题。在此处查看更多详细信息:这里

这会导致崩溃:例如,您有VC1(作为根VC)和VC2。您从VC1推到VC2,然后再弹回。现在,在VC1上进行滑动手势,然后立即再次推到VC2。对我来说,结果是崩溃。 或者您可以在从VC2弹回后在VC1上滑动多次,我的测试应用程序再次崩溃。 我必须注意到,我使用了“NULL”而不是“@selector(performCompletion)” 在VC1中的“viewDidAppear”中禁用“interactivePopGestureRecognizer”会导致其他错误。 - surfrider

1

有一个新的手势识别器 UIScreenEdgePanGestureRecognizer。你可以将它添加到你的视图中并分别处理(调用navigateBack),从而复制视图控制器导航行为。


0
你在 "navigateBack" 方法中做了什么?
使用这个方法的方式如下:
- (void)navigateBack
{
    [self.navigationController popViewControllerAnimated:YES];
}

没错,这就是 navigateBack 中的内容。我会把它添加到问题中,谢谢! - dlinsin

0
尝试将以下代码添加到自定义返回按钮中: self.navigationController.interactivePopGestureRecognizer.delegate = (id)self;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接