Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to subclass UINavigationBar correctly also using appearance

This is what I am trying to achieve: NavigationBar NB: Also with a title to the controller.

Some additional information:-

  1. This navigation bar will appear on around 10 view controllers.
  2. It is not part of a Navigation Controller, as not required to be.
  3. The button on the left is static (will always be on the navigation bar).
  4. The right button is not static and will either not exist or be different on the different View Controllers.
  5. The left button acts as a sliding menu (i.e. menu slides in underneath from left)
  6. I am using storyboard in the setup

Question What is the correct way to achieve this?

Existing Code I have tried to implement this, but I can only get one or the other of the buttons, without a title working. To implement the background I used the appearance API as below:

didFinishLaunching...

// Custom Navigation Bar appearance setup
[[UINavigationBar appearance] setTitleTextAttributes: [NSDictionary dictionaryWithObjectsAndKeys:
                                                       [UIColor colorWithRed:245.0/255.0 green:245.0/255.0 blue:245.0/255.0 alpha:1.0], UITextAttributeTextColor,
                                                       [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.5],UITextAttributeTextShadowColor,
                                                       [NSValue valueWithUIOffset:UIOffsetMake(0, 1)],
                                                       UITextAttributeTextShadowOffset,nil]];
// Used to deal with the rotation of the nav bar when implemented outside of Navigation Controller
[[UINavigationBar appearance] setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleHeight];
[[UINavigationBar appearance] setContentMode:UIViewContentModeScaleAspectFit];

// Set the background image
UIImage *imageBg = [[UIImage imageNamed: @"mainNavBar"] resizableImageWithCapInsets:UIEdgeInsetsMake(0,5,0,5)];
[[UINavigationBar appearance] setBackgroundImage:imageBg forBarMetrics:UIBarMetricsDefault];

// Used to push the title down slightly when in Landscape and NavBar outside of Navigation Controller
[[UINavigationBar appearance] setTitleVerticalPositionAdjustment:2 forBarMetrics:UIBarMetricsLandscapePhone];

I then subclassed UINavigationBar for the left button creation with the following: Subclass of UINavigationBar: awakeFromNib

UINavigationItem* ni = [[UINavigationItem alloc] init];
UIButton *leftButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 38.0f, 29.0f)];
[leftButton setImage:[UIImage imageNamed:@"menuBarItem"] forState:UIControlStateNormal];
[leftButton addTarget:nil action:@selector(menuItemPressed:) forControlEvents:UIControlEventTouchUpInside];
[leftButton setContentMode:UIViewContentModeScaleAspectFit];
[leftButton setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin];
UIBarButtonItem *b =[[UIBarButtonItem alloc] initWithCustomView:leftButton];
ni.leftBarButtonItem = b;
self.items = @[ni];

Then within the storyboard I add a NavigationBar to the VC in question and link to the correct subclass. I also add an additional button item to the navigation bar in the storyboard for that controller and link to an outlet. Then within the VC I try to update the title and right button with the below:

View Controller that holds the subclassed Nav Bar: viewDidLoad

// Set VC Title for NavBar
self.title  = NSLocalizedString(@"NavBarHomeTitle", @"Navigation Bar - Home page title");

// Setup the right navigation bar item
UIImage *addImage = [UIImage imageNamed:@"addGameButton"];
UIButton *addButton = [UIButton buttonWithType:UIButtonTypeCustom];
[addButton setFrame:CGRectMake(0, 0, addImage.size.width, addImage.size.height)];
[addButton setBackgroundImage:addImage forState:UIControlStateNormal];
[addButton addTarget:self action:@selector(addGameButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self.rightBarButtonItem setCustomView:addButton];

The result is a navigation bar with only the left button. Now I believe this is due to the awakeFromNib code above alloc init a new UINavigationItem therefore I cannot control the title and add a button to it. How can I complete this? Is this the best approach or are there others I cannot see any in-depth tutorials on how to approach this.

like image 454
StuartM Avatar asked May 04 '13 10:05

StuartM


People also ask

What is a uinavigationbar object?

A UINavigationBar object is a bar, typically displayed at the top of the window, containing buttons for navigating within a hierarchy of screens. The primary components are a left (back) button, a center title, and an optional right button.

How do I change the navigation bar in UIViewController?

Configure the appearance of the navigation bar using the navigationBar property on the UINavigationController object. Control the content of the navigation bar by setting the title and navigationItem properties on each UIViewController you push onto the navigation controller’s stack.

How do I change the style of a navigation bar?

Use the barStyle property to select the style. Any changes you make to other navigation bar appearance properties override those inferred from the bar style. Navigation bars are translucent by default; that is, their background color is semitransparent. You can make the navigation bar opaque by setting the isTranslucent property to false.

How does the uinavigationcontroller work?

The UINavigationController object creates, displays, and manages its associated navigation bar, and uses attributes of the view controllers you add to control the content displayed in the navigation bar. To control a navigation bar when using a navigation controller, the following steps are required:


1 Answers

Your better option is to use a navigation controller, it acts as the controller that interrogates the view controller it's currently displaying and updates the navigation bar.

Rather than subclass the navigation bar, you should subclass the navigation controller. Then whenever the displayed view controller changes you can set the left button item by adding it to the navigation item of that view controller. Each view controller can specify whatever right bar button item(s) it requires.

The simplest way to do this is for the navigation controller to act as its own delegate and implement navigationController:willShowViewController:. Using this method it can access the navigationItem of the passed view controller and set the leftBarButtonItem. You also have access to the other methods of the navigation and view controllers if required.

Each view controller would also, in viewDidLoad, set its self.navigationItem.rightBarButtonItem(s) to appropriate buttons for the requirements of its view. Such as your 'addGameButton' bar button.

Working this way, the appearance will work as you have it, the title of the view controller will work automatically and you have full control, and a number if methods in your navigation controller subclass, to perform your button and interaction customisations.

like image 199
Wain Avatar answered Sep 19 '22 13:09

Wain