在 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
Changing back button in iOS 7 disables swipe to navigate back
提问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 leftBarButtonItem
worked for me:
leftBarButtonItem
在为我分配工作后调用以下行:
self.navigationController.interactivePopGestureRecognizer.delegate = self;
Edit:This does not work if called in init
methods. It should be called in viewDidLoad
or 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,但它会导致几个错误:
- Push another viewController into the navigationController when swiping in from the left edge of the screen;
- Or, swipe in from the left edge of the screen when the topViewController is popping up from the navigationController;
- 从屏幕左边缘滑入时,将另一个 viewController 推入 navigationController 中;
- 或者,当 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 UIGestureRecognizerDelegate
method in self.navigationController.interactivePopGestureRecognizer.delegate
like 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;
}
}
}