1

I have subclassed UINavigationBar to have a custom navigation bar within my application. The bar is re-used on multiple view controllers with the same style Menu button as the left button item, which is why it is subclassed.

The subclass is then added to the View Controllers navigation bar in the storyboard.

This is the code within the UINavigationBar subclass:

- (void)drawRect:(CGRect)rect
{
    // Drawing code
    UIImage *image = [[UIImage imageNamed: @"mainNavBar"] resizableImageWithCapInsets:UIEdgeInsetsMake(0,5,0,5)];
    [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}

-(void)awakeFromNib {
    UIButton *leftButton = [[UIButton alloc]initWithFrame:CGRectMake(7.0f, 7.0f, 38.0f, 29.0f)];
    [leftButton setImage:[UIImage imageNamed:@"menuBarItem"] forState:UIControlStateNormal];
    [leftButton addTarget:nil action:@selector(menuItemPressed:) forControlEvents:UIControlEventTouchUpInside];
    [self addSubview:leftButton];
}

The issue is Rotation of the Device. I also have some code in appDidFinishLaunching using the appearance API for additional setup:

// 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];
// Used to push the title down slightly when in Landscape and NavBar outside of Navigation Controller
[[UINavigationBar appearance] setTitleVerticalPositionAdjustment:2 forBarMetrics:UIBarMetricsLandscapePhone];

When the device rotates it all works correctly in terms of the bar scaling in height as expected from 44 to 32px. However, the buttons still appear out side of the bar. enter image description here

I have looked through some other SO posts on this, but cannot figure how to complete this correctly: iPhone: UINavigationBar with buttons - adjust the height

UINavigationBar autoresizing

Ideally I do not want to have to deal with the auto rotation in a View Controller because this UINavigationBar is re-used through a large amount of VCs. Adding in auto rotation code would mean each of the VCs would potentially need this too?

EDIT - following answer If I change the awakeFromNib to include the following:

UINavigationItem* ni = [[UINavigationItem alloc] initWithTitle:@"Test"];
    UIImage *menuBgImage = [UIImage imageNamed:@"menuBarItem"];
    UIBarButtonItem *b =[[UIBarButtonItem alloc] initWithImage:menuBgImage landscapeImagePhone:menuBgImage style:UIBarButtonItemStylePlain target:nil action:@selector(menuItemPressed:)];
    ni.leftBarButtonItem = b;
    self.items = @[ni];

I have the issue of the UIBarButtonItemStylePlain ruining the image: enter image description here

If I complete the previous setup with initWithCustomView and use the leftButton from the original code. With the leftButton using the autoresize for height- I then get a badly stretched image in landscape?

enter image description here

EDIT 2 - Additional image per answer enter image description here

Community
  • 1
  • 1
StuartM
  • 6,743
  • 18
  • 84
  • 160
  • You have to set autoresizing of UIbButton that you are creating in awakeFromNib method and also enable autoresizesubviews property of navigatonBar. – fibnochi May 03 '13 at 16:19
  • Can you confirm how to accomplish this in an answer please? – StuartM May 03 '13 at 16:37
  • *** Illegal property type, c in invocation selector, _UIAppearance_setAutoresizesSubviews: when trying to set '[[UINavigationBar appearance] setAutoresizesSubviews:YES];' – StuartM May 03 '13 at 16:42

1 Answers1

0
[self addSubview:leftButton];

That's the problem. This is not how you add things to a UINavigationBar! You must start with a UINavigationItem and set its buttons to a UIBarButtonItem. The bar button items will be adjusted when the navigation bar is resized.

Here is a simple example to get you started (could go in your awakeFromNib):

UINavigationItem* ni = [[UINavigationItem alloc] initWithTitle:@"Test"];
UIBarButtonItem* b = [[UIBarButtonItem alloc] initWithTitle:@"Howdy"
    style:UIBarButtonItemStyleBordered
    target:self action:@selector(pushNext:)];
ni.leftBarButtonItem = b;
self.items = @[ni];

However, note that this is not going to work if you then use this UINavigationBar as part of a UINavigationController! The left bar button will be pushed off by the view controller's navigationItem. If this is part of a standard navigation interface, just have every navigation controller add the left bar button item.

Also you should not be implementing drawRect. Set the nav bar's background image instead.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Do you know more on starting with UINavigationItem that is not available in appearance API is it? – StuartM May 03 '13 at 16:34
  • I do not understand how to access the UINavigationItem that is created by the subclass from within the subclass of UINavigationBar. Please let me know any other information – StuartM May 03 '13 at 16:38
  • You are not doing `addSubview` using appearance API either. You are just doing it in the subclass. So I'm saying, instead of that, do it the right way: make a UINavigationItem, set its `leftBarButtonItem`, and push it onto the navigation bar. – matt May 03 '13 at 16:40
  • Thanks Matt. What is the correct way to implement this then? Completely through appearance API or parts with subclass too? I was unsure how to set the background from within the subclass other than drawInRect, or do you mean to set the background in the appearance API instead? – StuartM May 03 '13 at 16:47
  • It doesn't matter, since you've already got a subclass. Just call `setBackgroundImage` in your `awakeFromNib`. – matt May 03 '13 at 16:48
  • I have replaced the [image drawInRect... with [self setBackgroundImage:image forBarMetrics:UIBarMetricsDefault]; and now no background image shows at all? – StuartM May 03 '13 at 17:19
  • Unfortunately that doesnt work, the background does not show in either landscape or portrait. In regards to the button resizing I have edited the question with more information on the issues I face now – StuartM May 03 '13 at 17:33
  • Background resolved by not overriding drawRect and using self setBackground... in awakeFromNib. Specifically the not overriding drawRect makes it show, but still the resize issue – StuartM May 03 '13 at 18:32
  • Don't use UIBarButtonItemStylePlain. You should be making your bar button item with `initWithCustomView`, and the view should be a UIImageView containing your image. – matt May 03 '13 at 18:44
  • Yes, that is the last part of my edit above. I have tried with initWithCustomView loading either a UIButton or UIImageView and both have the same effect as shown in the final screenshot above. – StuartM May 03 '13 at 18:57
  • Set the image view's `contentMode` to something better, like maybe UIViewContentModeCenter. This will keep the image from being stretched when the image view is resized. You might need to experiment with different modes till you hit the right one... :) – matt May 03 '13 at 19:07
  • thanks, unfortunately not having much luck with this. I have gone through every option for contentMode and still the same issue. The image is either per the screenshot or the full original size (as it is portrait) which then means it is too large for the nav bar :/ – StuartM May 03 '13 at 19:12
  • Really? What about UIViewContentModeScaleAspectFit? Should keep the aspect correct while making it fit the smaller height. – matt May 03 '13 at 19:16
  • I have added an image showing the code/result to the question again – StuartM May 03 '13 at 19:19
  • Unless that is actually the correct re-sized image?? Looks slightly odd, and needs alignment now... I added resizable left and top margins so thought that should fit correctly into place – StuartM May 03 '13 at 19:20
  • Accepted as answer as decided to not provide these views in landscape, proves to difficult for something so simple :). I have some issues with title but will put a new question up, thanks for your help @matt – StuartM May 04 '13 at 10:18