簡體   English   中英

嘗試處理 iOS 中的“后退”導航按鈕操作

[英]Trying to handle “back” navigation button action in iOS

我需要檢測用戶何時點擊導航欄上的“后退”按鈕,以便在發生這種情況時執行一些操作。 我正在嘗試手動設置對此類按鈕的操作,如下所示:

[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因為 pop 是動畫的,我想立即處理后退按鈕而不是等到過渡完成。

didMoveToParentViewController的問題在於,一旦父視圖再次完全可見,它就會被調用,因此如果您需要在此之前執行某些任務,它將無法工作。

它不適用於驅動動畫手勢。 使用willMoveToParentViewController效果更好。

目標-c

- (void)willMoveToParentViewController:(UIViewController *)parent{
    if (parent == NULL) {
        // ...
    }
}

迅速

override func willMoveToParentViewController(parent: UIViewController?) {
    if parent == nil {
        // ...  
    }
}

這是dadachi的答案的Objective-C版本:

目標-C

- (void)didMoveToParentViewController:(UIViewController *)parent{
    if (parent == NULL) {
        NSLog(@"Back Pressed");
    }
}

設置 UINavigationBar 的委托,然后使用:

- (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 並實現這個委托 func (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()將被調用以決定控制器是否彈出。 如果未設置,它將像往常一樣彈出。

禁用UINavigationControllerinteractivePopGestureRecognizer是個好主意,否則手勢不會調用您的處理程序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM