How to create backBarButtomItem with custom view for a UINavigationController

前端 未结 14 932
余生分开走
余生分开走 2020-11-29 19:39

I have a UINavigationController into which I push several views. Inside viewDidLoad for one of these views I want to set the self.navigationI

相关标签:
14条回答
  • 2020-11-29 19:51

    You can use leftBarButtonItem instead of back button item. And to remove the default back button item set it to nil like follows;

    navigationController?.navigationBar.backIndicatorImage = nil
    navigationController?.navigationBar.backIndicatorTransitionMaskImage = nil
    
    let button = UIButton.init(type: .custom)
    button.imageView?.contentMode = UIViewContentMode.scaleAspectFit
    button.setImage(UIImage.init(named: "top_back"), for: UIControlState.normal)
    button.frame = CGRect.init(x: 0, y: 0, width: 75, height: 50) 
    button.addTarget(self, action: #selector(handleBackButton), for: .touchUpInside)
    
    let barButton = UIBarButtonItem.init(customView: button)
    self.navigationItem.leftBarButtonItem = barButton
    
    0 讨论(0)
  • 2020-11-29 19:55

    If your end goal is to simply replace the image used for the back button, you can use a new method on UIBarButtonItem available in iOS 5.0:

    setBackButtonBackgroundImage:forState:barMetrics:

    Apple Docs: http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIBarButtonItem_Class/Reference/Reference.html

    Here's a simple example that sets a custom background image for all back buttons in your app:

    UIImage *toolbarBackButtonBackgroundPortrait = [[UIImage imageNamed:@"toolbarBackButtonPortrait"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 17, 0, 6)];
    UIImage *toolbarBackButtonBackgroundLandscape = [[UIImage imageNamed:@"toolbarBackButtonLandscape"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 17, 0, 6)];
    
    [[UIBarButtonItem appearance] setBackButtonBackgroundImage:toolbarBackButtonBackgroundPortrait forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
    [[UIBarButtonItem appearance] setBackButtonBackgroundImage:toolbarBackButtonBackgroundLandscape forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone];
    
    0 讨论(0)
  • 2020-11-29 19:56

    I never been able to create a proper UIBarButtonItem with custom view and setBackBarButtonItem.

    Here's the solution i found : let net UINavigationControllerDelegate handles everything! The trick here is to call the popViewControllerAnimated: method of the viewController.navigationController so you don't have to create any custom method.

    - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
        if([navigationController.viewControllers count ] > 1) {
            UIView *backButtonView = [[UIView alloc] initWithFrame:CGRectMake(0,0,70,35)];
            UIButton *myBackButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
            [myBackButton setFrame:CGRectMake(0,0,70,35)];
            [myBackButton setImage:[UIImage imageNamed:@"back.png"] forState:UIControlStateNormal];
            [myBackButton setEnabled:YES];
            [myBackButton addTarget:viewController.navigationController action:@selector(popViewControllerAnimated:) forControlEvents:UIControlEventTouchUpInside];
            [backButtonView addSubview:myBackButton];
            [myBackButton release];
            UIBarButtonItem* backButton = [[UIBarButtonItem alloc] initWithCustomView:backButtonView];
            viewController.navigationItem.leftBarButtonItem = backButton;
            [backButtonView release];
            [backButton release];
        }
    }
    
    0 讨论(0)
  • 2020-11-29 19:57

    Set the backBarButtonItem before pushing the viewController with the navigationController. Setting the backBarButtonItem in viewDidLoad doesn't work.

    Say I have MyTableViewController. When the user taps a particular row I want to push AnotherViewController using the navigationController. The code looks something like this:

    // in MyTableViewController's tableView:didSelectRowAtIndexPath method...
    UIBarButtonItem *backButton = [[UIBarButtonItem alloc] 
                                   initWithImage:[UIImage imageNamed:@"yourImage.png"]
                                           style:UIBarButtonItemStyleBordered 
                                          target:nil 
                                          action:nil];
    
    self.navigationItem.backBarButtonItem = backButton;
    [backButton release];
    
    [self.navigationController pushViewController:anotherViewController];
    

    When anotherViewController is displayed the back button in the navigation bar will have @"yourImage.png" and the default back button style (rectangular arrow). Also note it's fine to pass nil as target. The button behaves like the back button.

    0 讨论(0)
  • 2020-11-29 19:59

    I too have been having problems with customView on a navigationItem.backBarButtonItem. I suspect it's probably just b0rked in the SDK.

    While the workarounds outlined here do work, I've come up with a solution which is a little more elegant: it still uses navigationItem.leftBarButtonItem, but takes care of it for you automagically (no more need for 'child' view controllers to need to know anything about their 'parent' and/or to manually set navigationItem.leftBarButtonItem).


    First up, have some class be a UINavigationControllerDelegate for the UINavigationController whose back button you're interested in. Then, in this class, set up something like the following willShowViewController delegate method:

    -(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
        // reference to view controller stack
        NSArray *viewControllers = [ navigationController viewControllers ];
        if( [ viewControllers count ] > 1 ){
            // the view controller we'll be linking to
            UIViewController *backViewController = [ viewControllers objectAtIndex: [ viewControllers count ] - 2 ];
            // create custom UIBarButtonItem
            UIBarButtonItem *leftButton = [[ UIBarButtonItem alloc ] initWithCustomView: someCustomView ];
            // set it as the leftBarButtonItem on the incoming viewcontroller
            viewController.navigationItem.leftBarButtonItem = leftButton;
            // tidy up
            [ leftButton release ];
        }
    }
    

    I had some further problems with this; it seems that UIBarButtonItem.action and UIBarButtonItem.target don't work when it's a navigationItem.leftBarButtonItem. So, you're left with a custom back button that doesn't actually go back. I'll leave responding to touches in your custom view as an exercise for the reader (I used a UIButton), but you'll need add this method to your delegate class:

    -(void)onDummyBackButtonTapped{
        [ someNavigationController popViewControllerAnimated: YES ];
    }
    

    and hook it up to fire when your custom view is tapped.

    0 讨论(0)
  • 2020-11-29 20:01

    I would be willing to bet that this is a bug on Apple's part as I am running into the exact same problem. The reason being is that I can get a custom UIBarButtonItem to appear, but only when I don't try to use the initWithCustomView: method. Per the API, the navigation controller checks the following things when a new view controller is pushed:

    1. If the new top-level view controller has a custom left bar button item, that item is displayed. To specify a custom left bar button item, set the leftBarButtonItem property of the view controller’s navigation item.
    2. If the top-level view controller does not have a custom left bar button item, but the navigation item of the previous view controller has a valid item in its backBarButtonItem property, the navigation bar displays that item.
    3. If a custom bar button item is not specified by either of the view controllers, a default back button is used and its title is set to the value of the title property of the previous view controller—that is, the view controller one level down on the stack. (If there is only one view controller on the navigation stack, no back button is displayed.)

    My case (as well as yours) is 2. I specify code exactly the same as yours (i.e., creating a UIButton, setting its image properties for various states, creating a UIBarButtonItem, initializing it with the UIButton, then setting my current view controller's backBarButtonItem property to the UIBarButtonItem); however, when I later push my view controller, nothing at all is displayed on the left-hand side of my navigation controller. Strangely, I can click where the "Back" button should be, and it pops the view controller.

    Interestingly, if I create a UIBarButtonItem using the initWithTitle:style:target:action: method instead of the initWithCustomView: method, it does show a custom button with a custom title. Also, as Travis mentioned, using the leftBarButtonItem property instead works just fine. I'd rather adhere to the sanctioned logic, however, by specifying the "Back" button for the current view controller -- to be displayed later when a new view controller is pushed -- instead of creating a left button for the next view controller, which, arguably, should have no concern for anything pertaining to the view controller that came before it. :-\

    0 讨论(0)
提交回复
热议问题