我需要检测用户何时点击导航栏上的“后退”按钮,以便在发生这种情况时执行一些操作。我正在尝试手动设置此类按钮的操作,这样:
[self.navigationItem.backBarButtonItem setAction:@selector(performBackNavigation:)];
- (void)performBackNavigation:(id)sender
{
// Do operations
[self.navigationController popViewControllerAnimated:NO];
}
我首先将该代码放置在视图控制器本身中,但我发现
self.navigationItem.backBarButtonItem
似乎是nil
,所以我将相同的代码移至父视图控制器,这将前者推送到导航堆栈。但我也无法让它发挥作用。我读过一些关于这个问题的帖子,其中一些说选择器需要在父视图控制器上设置,但对我来说它无论如何都不起作用......我可能做错了什么?
谢谢
使用
VIewWillDisappear
方法尝试此代码来检测 NavigationItem 的后退按钮的按下:
-(void) viewWillDisappear:(BOOL)animated
{
if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound)
{
// Navigation button was pressed. Do some stuff
[self.navigationController popViewControllerAnimated:NO];
}
[super viewWillDisappear:animated];
}
或者还有另一种方法来获取导航返回按钮的操作。
为后退按钮的 UINavigationItem 创建自定义按钮。
例如:
在 ViewDidLoad 中:
- (void)viewDidLoad
{
[super viewDidLoad];
UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle:@"Home" style:UIBarButtonItemStyleBordered target:self action:@selector(home:)];
self.navigationItem.leftBarButtonItem=newBackButton;
}
-(void)home:(UIBarButtonItem *)sender
{
[self.navigationController popToRootViewControllerAnimated:YES];
}
斯威夫特:
override func willMoveToParentViewController(parent: UIViewController?)
{
if parent == nil
{
// Back btn Event handler
}
}
override func didMoveToParentViewController(parent: UIViewController?) {
if parent == nil {
//"Back pressed"
}
}
也许这个答案不符合你的解释,但符合问题标题。当您想知道何时点击了
UINavigationBar
上的后退按钮时,这很有用。
在这种情况下,您可以使用
UINavigationBarDelegate
协议并实现以下方法之一:
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item;
- (void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item;
当调用
didPopItem
方法时,这是因为您点击了后退按钮或使用了 [UINavigationBar popNavigationItemAnimated:]
方法并且导航栏确实弹出了该项目。
现在,如果您想知道什么操作触发了
didPopItem
方法,您可以使用标志。
通过这种方法,我不需要手动添加带有箭头图像的左栏按钮项目,以使其类似于 iOS 后退按钮,并且能够设置我的自定义目标/操作。
我有一个视图控制器,它有一个页面视图控制器和一个自定义页面指示器视图。我还使用自定义 UINavigationBar 来显示标题以了解我在哪个页面,并使用后退按钮返回上一页。我还可以在页面控制器上滑动到上一页/下一页。
#pragma mark - UIPageViewController Delegate Methods
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {
if( completed ) {
//...
if( currentIndex > lastIndex ) {
UINavigationItem *navigationItem = [[UINavigationItem alloc] initWithTitle:@"Some page title"];
[[_someViewController navigationBar] pushNavigationItem:navigationItem animated:YES];
[[_someViewController pageControl] setCurrentPage:currentIndex];
} else {
_autoPop = YES; //We pop the item automatically from code.
[[_someViewController navigationBar] popNavigationItemAnimated:YES];
[[_someViewController pageControl] setCurrentPage:currentIndex];
}
}
}
然后我实现 UINavigationBar 委托方法:
#pragma mark - UINavigationBar Delegate Methods
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
if( !_autoPop ) {
//Pop by back button tap
} else {
//Pop from code
}
_autoPop = NO;
return YES;
}
在本例中,我使用
shouldPopItem
,因为弹出是动画的,我想立即处理后退按钮,而不是等到转换完成。
didMoveToParentViewController
的问题在于,一旦父视图再次完全可见,它就会被调用,因此如果您需要在此之前执行一些任务,它将无法工作。
并且它不适用于驱动动画手势。 使用
willMoveToParentViewController
效果更好。
Objective-c
- (void)willMoveToParentViewController:(UIViewController *)parent{
if (parent == NULL) {
// ...
}
}
斯威夫特
override func willMoveToParentViewController(parent: UIViewController?) {
if parent == nil {
// ...
}
}
- (void)didMoveToParentViewController:(UIViewController *)parent{
if (parent == NULL) {
NSLog(@"Back Pressed");
}
}
设置UINavigationBar的delegate,然后使用:
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
//handle the action here
}
其他解决方案都不适合我,但这个解决方案:
创建您自己的 UINavigationController 子类,使其实现 UINavigationBarDelegate (无需手动设置导航栏的委托),添加 UIViewController 扩展来定义按下后退按钮时调用的方法,然后在 UINavigationController 中实现此方法子类:
func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
self.topViewController?.methodToBeCalledOnBackButtonPress()
self.popViewController(animated: true)
return true
}
在 Swift 4 或更高版本中:
override func didMove(toParent parent: UIViewController?) {
if parent == nil {
//"Back pressed"
}
}
设置 UINavigationControllerDelegate 并实现此委托函数(Swift):
func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
if viewController is <target class> {
//if the only way to get back - back button was pressed
}
}
使用自定义
UINavigationController
子类,该子类实现 shouldPop
方法。
在斯威夫特:
class NavigationController: UINavigationController, UINavigationBarDelegate
{
var shouldPopHandler: (() -> Bool)?
func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool
{
if let shouldPopHandler = self.shouldPopHandler, !shouldPopHandler()
{
return false
}
self.popViewController(animated: true) // Needed!
return true
}
}
设置后,您的
shouldPopHandler()
将被调用来决定控制器是否弹出。未设置时,它会像往常一样弹出。
禁用
UINavigationController
s interactivePopGestureRecognizer
是个好主意,否则手势不会调用您的处理程序。
以下是文档的内容:
如果导航栏中已出现后退按钮,则设置此属性将替换其操作,而不修改其外观。
因此,在您的
viewDidLoad
或适当的地方,您可以添加以下代码:
navigationItem.backAction = UIAction { [weak self] _ in
// Handle your other logic here for back button tap
self?.navigationController?.popViewController(animated: true)
}