iOS 5 Back Button Size
Asked Answered
R

2

2

I'm using the iOS 5 UIAppearance protocol to use a custom navigation bar back button as seen here. Unlike other methods I've found, this one is the best since it preserves the default back button animations and behaviours.

The only problem is that I can't change its size or set it to not clip subviews. Here's what's happening:

Clipping Image

A is intended behaviour, B is default style, C is the clipped result.

Unfortunately, it's not as easy as setting UIBarButtonItem to clipsToBounds=NO.

Does anyone know how to solve this issue? Thanks!

Reams answered 6/5, 2012 at 14:32 Comment(3)
Have you tried UIBarButtonItem.superview.clipsToBounds = NO? (Or superview.superview...) Because the navigation bar is not intended to be larger than it is already. So anything you'll try will be a 'hack'. And if it is a hack, then this is the 'standard' way to go :-)Adan
What you are recommending is not possible since UIBarButtonItem doesn't inherit from UIView. However, I have tried setting self.navigationController.navigationItem.backBarButtonItem.customView.clipsToBounds = NO; and self.navigationItem.backBarButtonItem.customView.clipsToBounds = NO;. I assume you meant that the UIBarButtonItem is not intended to be larger as I'm not touching the nav bar itself.Reams
Yes you are right! What I generally mean is traversing the view hierarchy and finding out which one clips. Also you may have to take care of iOS < 5 and iOS >=5 differently. I actually mean the the navigation bar isn't meant to be larger, because the bar items are not limited, the navigation bar is what limits them. It has hardcoded padding and the leftover is the space for the buttons.Adan
M
5

As you've discovered, UIAppearance proxies won't let you adjust the dimensions of the button itself: the list of supported appearance methods for UIBarButtonItem is given in the documentation, and whilst it includes metrics for the title label itself the button is off-limits.

For what it's worth, the button itself is actually 44 pts (88 pixels, if you're in retina) high in terms of touchable area, it's just the button graphic is smaller than that.

If you're dead set on what amounts to a 3 pt difference in height then the best option is probably going to be to create your own custom button and use the UINavigationItem setLeftBarButtonItem method. As you point out, you're going to need to implement a short method attached to that button that implements popNavigationController to ensure the correct behavior remains.

Update: I've just found out that if you keep your back button around you can, in fact, animate it to have it slide in a similar fashion to a standard back button. In the code below self.backButton is the UIButton you would have used in your initWithCustomView UIBarButtonItem method.

- (void)viewWillDisappear:(BOOL)animated {
    [UIView animateWithDuration:0.3 
                     animations:^{
                         self.backButton.frame = CGRectMake(self.backButton.frame.origin.x+100, 
                                                            self.backButton.frame.origin.y, 
                                                            self.backButton.frame.size.width, 
                                                            self.backButton.frame.size.height);
                     }];
}

...this will trigger whenever the view controller disappears (ie, when popped and pushed), but you could hook into the UINavigationController delegate to only trigger it when the nav controller is popped instead. It definitely seems to move the button when controller is pushed, although I've only tested it on the simulator.

Mathilda answered 6/5, 2012 at 15:7 Comment(2)
Thanks for confirming my suspicions about UIAppearance, @lxt. Unfortunately, by setting a custom leftBarButtonItem, I lose the backBarButtonItem animation (horizontal sliding) and since UIBarButtonItem doesn't inherit from UIView, I can't animate it myself.Reams
Try the code I just posted, might help you with the animation. Seems to work for me.Mathilda
R
2

I ended up using a custom view controller class for every VC I'm using in my navigation controller.

OEViewController.h

#import <UIKit/UIKit.h>
#import "OEBarButtonItem.h"

@interface OEViewController : UIViewController

@property (nonatomic, retain) UIButton *backButton;
@property (atomic) BOOL pushed;

- (void)pushViewController:(UIViewController*)vc;

@end

OEViewController.m

#import "OEViewController.h"

#define ANIMATION_DURATION 0.33

@implementation OEViewController
@synthesize backButton, pushed;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    pushed=YES;
    self.navigationItem.hidesBackButton = YES;

    backButton = [OEBarButtonItem backButtonWithTitle:[(UIViewController*)[self.navigationController.viewControllers objectAtIndex:[self.navigationController.viewControllers count]-2] title]];

    [backButton addTarget:self action:@selector(backButtonPressed:) forControlEvents:UIControlEventTouchUpInside];

    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    if (pushed) {
        self.backButton.frame = CGRectMake(self.backButton.frame.origin.x+100, 
                                           self.backButton.frame.origin.y+6, 
                                           self.backButton.frame.size.width, 
                                           self.backButton.frame.size.height);
        [UIView animateWithDuration:ANIMATION_DURATION 
                         animations:^{
                             self.backButton.frame = CGRectMake(self.backButton.frame.origin.x-100, 
                                                                self.backButton.frame.origin.y, 
                                                                self.backButton.frame.size.width, 
                                                                self.backButton.frame.size.height);
                         }];
        pushed=NO;
    } else {
        self.backButton.frame = CGRectMake(self.backButton.frame.origin.x-100, 
                                           self.backButton.frame.origin.y, 
                                           self.backButton.frame.size.width, 
                                           self.backButton.frame.size.height);
        [UIView animateWithDuration:ANIMATION_DURATION 
                         animations:^{
                             self.backButton.frame = CGRectMake(self.backButton.frame.origin.x+100, 
                                                                self.backButton.frame.origin.y, 
                                                                self.backButton.frame.size.width, 
                                                                self.backButton.frame.size.height);
                         }];
    }
}

- (void)backButtonPressed:(id)sender {
    [self.navigationController popViewControllerAnimated:YES];
    [UIView animateWithDuration:ANIMATION_DURATION 
                     animations:^{
                         self.backButton.frame = CGRectMake(self.backButton.frame.origin.x+100, 
                                                            self.backButton.frame.origin.y, 
                                                            self.backButton.frame.size.width, 
                                                            self.backButton.frame.size.height);
                     }];
}

- (void)pushViewController:(UIViewController*)vc {
    [self.navigationController pushViewController:vc animated:YES];
    [UIView animateWithDuration:ANIMATION_DURATION 
                     animations:^{
                         self.backButton.frame = CGRectMake(self.backButton.frame.origin.x-100, 
                                                            self.backButton.frame.origin.y, 
                                                            self.backButton.frame.size.width, 
                                                            self.backButton.frame.size.height);
                     }];
}

@end

This has the added benefit of working with iOS 4.0+ as opposed to using UIAppearance.

Thanks to @lxt for his help!

Reams answered 8/5, 2012 at 2:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.