12

I've done the tutorial at my blog, so I know how to make a stretchable button that can display the bottom (stack) viewcontroller's title. But what I was hoping to do is have icons (like a house for HOME) and no text and not resize.

Using my custom image and this code below, I get a stretched version (not wanted) with title over top (not wanted) and it does tint/highlight when clicked (is good);

UIImage *backButtonImage = [UIImage imageNamed:@"backButton_30.png"];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:backButtonImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];

screen shot 1

Now, I've searched on here and read all the similar questions which return old answers, and have strange results for me. Here is the code I tried;

  UIImage *backButtonImage = [UIImage imageNamed:@"backButton_30.png"];
  UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithImage:backButtonImage style:UIBarButtonItemStyleBordered target:nil action:nil];
  self.navigationItem.backBarButtonItem = backButton;

This method doesn't stretch out my custom image button (is good), nor does it show text (what I want) however there is still the original blue button under it (WTF), and my custom button doesn't tint when clicked, only the blue button under it does!

screen shot 2

Please help, what am I missing?

*UPDATE

I've fixed it up a bit by using a resizable image. This forces it not to 'stretch'

UIImage *backButtonHomeImage = [[UIImage imageNamed:@"backButtonHomeWhite_30.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:backButtonHomeImage  forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];

To fix the title showing up on the button I had to do

self.title =@" ";

Now this is a bit of a dirty fix but it seems to be working. The only problem left now is that I want a different back button on different views, and this method is causing some trouble; the last view that sets the button over-rides all other views. So in the end, depending on how you navigate through the app, returning to a previous view has the wrong back button and it never resets to the correct one.


UPDATE 2: POTENTIAL IDEA:

Would the following be a reasonable solution, or is it a hack that is liable to break something?

Hiding the default back button, like so,

[self.navigationItem setHidesBackButton:YES animated:NO];

...and then using a custom UIBarButtonItem, with a button in the style I actually want placed in the location of the back button, that sends a popViewControllerAnimated: message to the UINavigationController when tapped.

If you know of a more robust solution please do share, thank you.

Mazyod
  • 22,319
  • 10
  • 92
  • 157
RobDigital
  • 515
  • 1
  • 7
  • 19
  • Can't you just change it from the Attributes Inspector? – nemesis May 25 '12 at 16:56
  • I wish I knew how... I've selected the first view controller in storyboard, then went to attribute inspector and I do actually see a box under navigation item that says back button, however I have no idea how to use that; I've tried typing in the image name, but it doesn't appear to do anything. Any suggestions? – RobDigital May 25 '12 at 21:08
  • There's another approach to solve this - you could drag a generic button to the navigation bar, and then play with the custom images and names.. I hope this helps you! – nemesis May 26 '12 at 10:03
  • @nemesis Would there then be any way to then make that button assume the behaviour of the back button? – Jon Cox Sep 06 '12 at 13:48

5 Answers5

13

Assuming that your current solution

UIImage *backButtonHomeImage = [[UIImage imageNamed:@"backButtonHomeWhite_30.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:backButtonHomeImage  forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];

is acceptable to you, so the only problem left is how to update that button appeareance when you go back and forth between your views, an approach that could work is executing the code above in each of your controllers' viewWillAppear: method:

- (void)viewWillAppear:(BOOL)animated {
    UIImage *backButtonHomeImage = [[UIImage imageNamed:@"backButtonHomeWhite_30.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
    [[UIBarButtonItem appearance] setBackButtonBackgroundImage:backButtonHomeImage  forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
}

If you are not satisfied with your current approach to having a custom UIBarButtonItem, the way to go is initializing your bar button item with initWithCustomView:. In this case, you can specify, e.g., a UIImageView with the image you like and it should work:

UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithCustomView:[UIImageView ...]];

Hope this helps.

sergio
  • 68,819
  • 11
  • 102
  • 123
9

For iOS 5+ use [[UIBarButtonItem appearance] setBackButtonBackgroundImage:[UIImage imageNamed:@"someimage.png"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault].

Andrew Theis
  • 933
  • 7
  • 15
  • As originally posted, this is what I've already tried and I get a stretched version (not wanted) with title over top (not wanted). – RobDigital Jun 01 '12 at 20:59
  • 1
    Your image needs to be the same height / width as Apple's. You may also want to create a resizable image using `[[UIImage imageNamed:@"someimage.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(6, 6, 6, 6)]`. The actual image needs to be the same height as Apple's, but the width should only be as large as necessary to fit the left & right caps + 1px in the middle which will be stretched out programmatically to fit the text. – Andrew Theis Jun 14 '12 at 05:17
  • 2
    Thanks for the suggestion Andrew, however you didn't address the main problem of having different custom back buttons on each view with different images and NO TEXT. – RobDigital Aug 28 '12 at 18:12
  • @AndrewTheis what height is apples? – Piotr Tomasik Feb 22 '13 at 20:50
  • @Piotr: Apple's is 30 points tall (so 30px non-retina, 60px retina). ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @RobDigital: For that you will have to manually set the `self.navigationItem.leftBarButtonItem` on a `UIViewController` to your own `UIBarButtonItem`. You can create one using `initWithCustomView` to completely customize the UI, or use `appearanceWhenContainedIn` to customize the back button image on a specific view. You will need to use the `initWithCustomView` method if you want to get rid of the title. Apple recommends, however, that your back buttons be contextual whenever possible. – Andrew Theis Mar 12 '13 at 21:55
  • @AndrewTheis Thanks so much for your excellent comment. Making the image 'resizableImageWithCapInsets' fixed an issue I was stuck on for about an hour! – braden May 20 '13 at 23:32
  • @RobDigital couldn't you have just combined that with: [[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -60) forBarMetrics:UIBarMetricsDefault]; to remove the text? – Rambatino May 25 '14 at 14:50
3

Some code i used in a project:

UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *btnImg = [UIImage imageNamed:@"ButtonRetourInactive"];
[btn setImage:btnImg forState:UIControlStateNormal];

btn.frame = CGRectMake(0, 0, btnImg.size.width, btnImg.size.height);
[btn addTarget:self action:@selector(goBack:) forControlEvents:UIControlEventTouchUpInside];
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:btn] autorelease];

Note, this works on iOS 4 and 3 aswell.

TegRa
  • 519
  • 3
  • 10
0

if You are using story boards , its too easy . take a round rectangular button and place it on the navigation bar . then double click the button( on selecting,at first, it just shows attributes of bar button , but by selecting twice , you can change all its properties as if you are customizing a regular UI button) .

shashank
  • 123
  • 14
0

UIAppearance is no use in this case.

I tried to use: - [UIBarButtonItem initWithCustomView:]. The view here you can add your background image and title, whatever you want.

scorpiozj
  • 2,687
  • 5
  • 34
  • 60