确认UINavigationController上的返回button

我正在使用UINavigationController的应用程序的故事板。 我想添加一个确认对话框到默认的后退button,所以用户不会意外退出。 有没有办法做到这一点? 我发现,当UINavigationController自动创build后,我不能简单地访问后退button。

有任何想法吗?

不幸的是,你不能以这种方式拦截后退button。 最接近的传真是使用您自己的UIBarButtonItem设置为navigationItem.leftBarButtonItem并设置一个动作来显示您的警报等。我有一个graphicsdevise器创buildbutton图像看起来像标准的后退button。

另外,我需要拦截后退button的原因不同。 我敦促你重新考虑这个deviseselect。 如果您正在呈现一个视图,用户可以进行更改,并希望他们可以select保存或取消恕我直言,最好使用“保存”和“取消”button与后退button与警报。 警报通常很烦人。 或者,清楚地说明用户所做的更改是在他们做出的时候进行的。 那么这个问题是没有意义的。

我如何解决这种情况是通过将leftBarButtonItem设置为UIBarButtonSystemItemTrash样式(使其立即显而易见,他们将删除草稿项目)并添加一个确认删除的警报视图。 因为你设置了一个自定义的leftBarButtonItem它不会像后退button,所以它不会自动popup视图!

在代码中:

 - (void)viewDidLoad { // set the left bar button to a nice trash can self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(confirmCancel)]; [super viewDidLoad]; } - (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex { if (buttonIndex) { // The didn't press "no", so pop that view! [self.navigationController popViewControllerAnimated:YES]; } } - (void)confirmCancel { // Do whatever confirmation logic you want here, the example is a simple alert view UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Warning" message:@"Are you sure you want to delete your draft? This operation cannot be undone." delegate:self cancelButtonTitle:@"No" otherButtonTitles:@"Yes", nil]; [alert show]; } 

这真的很简单! 我没有看到大问题,tbh:p

不过,我必须添加一个免责声明。 这样做违反了默认的导航行为,苹果可能不喜欢开发人员这样做。 我还没有提交任何应用程序(但),所以我不知道苹果是否会允许你的应用程序在商店做这件事,但被警告;)

更新:每个人都有好消息! 与此同时,我已经发布了一个应用程序( Appcident )到这个行为的App Store,苹果似乎并不介意。

其实,你可以find后退button视图,并添加UITapGestureRecognizer它。

如果你看这个图像: 返回按钮屏幕 使用这个代码:

 @interface UIView (debug) - (NSString *)recursiveDescription; @end @implementation newViewController ... NSLog(@"%@", [self.navigationController.navigationBar recursiveDescription]); 

您可以了解如何查找后退button的视图。 它始终是导航栏的子视图数组中的最后一个。

 2012-05-11 14:56:32.572 backBtn[65281:f803] <UINavigationBar: 0x6a9e9c0; frame = (0 20; 320 44); clipsToBounds = YES; opaque = NO; autoresize = W; layer = <CALayer: 0x6a9ea30>> | <UINavigationBarBackground: 0x6aa1340; frame = (0 0; 320 44); opaque = NO; autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x6aa13b0>> | <UINavigationButton: 0x6d6dde0; frame = (267 7; 48 30); opaque = NO; layer = <CALayer: 0x6d6d9f0>> | | <UIImageView: 0x6d70400; frame = (0 0; 48 30); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x6d6d7d0>> | | <UIButtonLabel: 0x6d70020; frame = (12 7; 23 15); text = 'Edit'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x6d6dec0>> | <UINavigationItemView: 0x6d6d3a0; frame = (160 21; 0 0); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x6d6d3f0>> | <UINavigationItemButtonView: 0x6d6d420; frame = (5 7; 139 30); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x6d6d4e0>> 

所以我用:

 UIView *backButton = [[navBar subviews] lastObject]; [backButton setUserInteractionEnabled:YES]; UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(alertMsg)]; [tapGestureRecognizer setNumberOfTapsRequired:1]; [backButton addGestureRecognizer:tapGestureRecognizer]; 

点击返回button和voilà: 后退按钮被轻敲

这是一个解决方法:(testingiOS10和11)

添加点击手势识别器到导航栏:

 let tap = UITapGestureRecognizer(target: self, action: #selector(onBackPressed(gestureRecognizer:))) tap.cancelsTouchesInView = true self.navigationController?.navigationBar.addGestureRecognizer(tap) 

cancelsTouchesInView = true确保后退button不会获​​得触摸事件。

处理手势:

 @objc func onBackPressed(gestureRecognizer: UITapGestureRecognizer) { guard gestureRecognizer.location(in: gestureRecognizer.view).x < 100 else { return } // ... back button is pressed do what you wanted to 

而不是使用100作为幻数,您可以find包含后退button的视图,并使用它的框架检测触摸。

我同意XJones。 UINavigationController有其局限性。 使用leftBarButtonItem是最直接的解决scheme。

如果你想有一个后退button,你不想完全重新devise你的用户界面,你可以使用UINavigationBar组件来编写你自己的导航控制器。 这并不困难。

您也可以尝试inheritanceUINavigationController并重写popViewControllerAnimated: 但不知道这是否会奏效。

下面是你需要做的,以便轻松地制作一个自定义后退button,复制iPhone和iPad上的默认后退button的外观,代码明确写出,因为我想我会在这里再次寻找这个。

把下面的函数用UINavigationController放在相关UIViewController的实现(.m)文件中,然后在viewDidLoad中运行[self setupBackButton];

无论您想要使用后退button,请放入backButtonPressed函数。

 - (void)setupBackButton { UIImage *leftArrowImage; UIImage *pressedLeftArrowImage; UIButton *customBackButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 48, 30)]; [customBackButton setAutoresizingMask:UIViewAutoresizingNone]; customBackButton.titleLabel.font=[UIFont boldSystemFontOfSize:12]; [customBackButton setTitle:@"Back" forState:UIControlStateNormal]; [customBackButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled]; [customBackButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 5, 0, 0)]; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { leftArrowImage = [UIImage imageNamed:@"UINavigationBarSilverBack.png"]; pressedLeftArrowImage = [UIImage imageNamed:@"UINavigationBarSilverBackPressed.png"]; } else { leftArrowImage = [UIImage imageNamed:@"UINavigationBarDefaultBack.png"]; pressedLeftArrowImage = [UIImage imageNamed:@"UINavigationBarDefaultBackPressed.png"]; } UIImage *stretchableLeftArrowImage = [leftArrowImage stretchableImageWithLeftCapWidth:15.0 topCapHeight:0]; UIImage *stretchablePressedLeftArrowImage = [pressedLeftArrowImage stretchableImageWithLeftCapWidth:15.0 topCapHeight:0]; [customBackButton setBackgroundColor:[UIColor clearColor]]; [customBackButton setBackgroundImage:stretchableLeftArrowImage forState:UIControlStateNormal]; [customBackButton setBackgroundImage:stretchablePressedLeftArrowImage forState:UIControlStateHighlighted]; [customBackButton addTarget:self action:@selector(backButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; UIBarButtonItem *aCustomBackButtonItem = [[UIBarButtonItem alloc] initWithCustomView:customBackButton]; [[self navigationItem] setLeftBarButtonItem:aCustomBackButtonItem]; } - (void)backButtonPressed:(id)sender { NSLog(@"back button pressed"); } 

要从iOS获得确切的buttonpng,我推荐UIKit Artwork Extractor 。 运行项目并在iPad Retina模拟器上保存图像,然后在iPad非视网膜模拟器上保存图像后,在模拟器文件夹中的“Common”文件夹中查找出现在桌面上的标题。 文件名“UINavigationBar …返回(@ 2x).png”和“UINavigationBar … BackPressed(@ 2x).png”是你想要的。

为了方便起见,我还附加了上面代码中使用的默认iOS(iPhone和iPad)后退buttonpng 。 请注意,使用iOS更新时,默认后端barbuttonitems的外观可能会更改…