views:

16865

answers:

14

I'd love to create a "back" left-arrow-bezel button in a UIToolbar.

As far as I can tell, the only way to get one of these is to leave UINavigationController at default settings and it uses one for the left bar item. But there's no way I can find to create one as a UIBarButtonItem, so I can't make one in a standard UIToolbar, even though they're very similar to UINavigationBars.

I could manually create it with button images, but I can't find the source images anywhere. They have alpha-channel edges, so screenshotting and cutting won't get very versatile results.

Any ideas beyond screenshotting for every size and color scheme I intend to use?

Update: PLEASE STOP dodging the question and suggesting that I shouldn't be asking this and should be using UINavigationBar. My app is Instapaper Pro. It shows only a bottom toolbar (to save space and maximize readable content area), and I wish to put a left-arrow-shaped Back button in the bottom.

Telling me that I shouldn't need to do this is not an answer and certainly doesn't deserve a bounty.

A: 

Well, you don't have to have a different button for every size, you can use -[UIImage stretchableImageWithLeftCapWidth:topCapHeight:], but the only thing I've found is custom images.

Ben Gottlieb
Right, that's the sort of thing I had in mind, but it'd be nice to get the source image - and I can't find it anywhere.
Marco
A: 

Why are you doing this? If you want something that looks like a navigation bar, use UINavigationBar.

Toolbars have specific visual style associated with them. The Human Interface Guidelines for the iPhone state:

A toolbar appears at the bottom edge of the screen and contains buttons that perform actions related to objects in the current view.

It then gives several visual examples of roughly square icons with no text. I would urge you to follow the HIG on this.

Colin Barrett
I'm aware of this, thank you. However, I believe my intended use is appropriate. Can you be more helpful, assuming that I really do want to do what I asked about?
Marco
If you're putting it at the top of the screen, it's being used wrong. Compare the gradients and borders between the UINavigationBar and the UIToolbar, and you'll see that they're slightly different. You definitely want to use a UINavigationBar at the top of the screen.
NilObject
I'm putting it on the bottom.
Marco
A: 

I agree with Colin. Putting navigation controls in a toolbar violates the HIG, is confusing to the user, and, to be honest, doesn't make a lot of sense. Use a UINavigationController and let it do the heavy lifting for you.

August
Please stop offering answers like this. It's not helpful. Please trust me that there's a valid reason why I'd like to do this instead of using a UINavigationBar.
Marco
It doesn't matter what YOUR reason is, other readers will definitely find it useful. And when your (or someone else's) app gets rejected by the App Store for non-adherance to the HIG, answers like this will prove extremely helpful. Sometimes the best answer to a question is "Don't do it."
August
Look at Safari, it uses navigation in a UIToolbar
Domness
+15  A: 

I used the following psd that I derived from http://www.teehanlax.com/blog/?p=447

http://www.chrisandtennille.com/pictures/backbutton.psd

I then just created a custom UIView that I use in the customView property of the toolbar item.

Works well for me.

Hope that helps a little

chris.

PyjamaSam
Does this PNG work if I have a blue navigator bar? Will iphone recolor it? Or will I need to change the colors in the PNG?
jm
The PSD I uploaded is for a black toolbar. I haven't tried much with the blue ones as my app doesn't use that. But from what I know the tool bar won't re-colour it as needed.chris.
PyjamaSam
A: 

If you want to avoid drawing it yourself, you could use the undocumented class: UINavigationButton with style 1. This could, of course, stop your application from being approved... /John

John Lane
+2  A: 

You can find the source images by extracting them from Other.artwork in UIKit ${SDKROOT}/System/Library/Frameworks/UIKit.framework/Other.artwork. The modding community has some tools for extracting them, here. Once you extract the image you can write some code to recolor it as necessary and set it as the button image. Whether or not you can actually ship such a thing (since you are embedding derived artwork) might be a little dicey, so maybe you want to talk to a lawyer.

Louis Gerbarg
How do you recolor buttons?
DenNukem
+4  A: 

I'm not sure if this would work, but you could try creating a UINavigationController with the default settings to create the button, find the button in the navigation controller's subview hierarchy, call removeFromSuperview on it, destroy the navigation controller, and then add the button as a subview of your toolbar. You may also need to retain and the button before calling removeFromSuperview (and then release it after adding it as subview of your toolbar) to avoid it being deallocated during the process.

Adam Rosenfield
that's just wrong. I mean morally. +1.
Yar
+1  A: 

To create an image for the UIToolbar, make a png in photoshop and WHERE EVER there is ANY colour it puts it white, and where it's alpha = 0 then it leaves it alone.

The SDK actually put's the border around the icon you have made and turns it white without you having to do anything.

See, this is what I made in Photoshop for my forward button (obviously swap it around for back button):

http://twitpic.com/1oanv

and this is what it appeared like in Interface Builder

http://twitpic.com/1oaoa

Domness
+1  A: 

The Three20 library has a way to do this:

  UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle: @"Title" style:UIBarButtonItemStylePlain 
                                                                target:self action:@selector(foo)];

  UIColor* darkBlue = RGBCOLOR(109, 132, 162);

  TTShapeStyle* style = [TTShapeStyle styleWithShape:[TTRoundedLeftArrowShape shapeWithRadius:4.5] next:
    [TTShadowStyle styleWithColor:RGBCOLOR(255,255,255) blur:1 offset:CGSizeMake(0, 1) next:
    [TTReflectiveFillStyle styleWithColor:darkBlue next:
    [TTBevelBorderStyle styleWithHighlight:[darkBlue shadow]
                                     shadow:[darkBlue multiplyHue:1 saturation:0.5 value:0.5]
                                      width:1 lightSource:270 next:
    [TTInsetStyle styleWithInset:UIEdgeInsetsMake(0, -1, 0, -1) next:
    [TTBevelBorderStyle styleWithHighlight:nil shadow:RGBACOLOR(0,0,0,0.15)
                                        width:1 lightSource:270 next:nil]]]]]];

  TTView* view = [[[TTView alloc] initWithFrame:CGRectMake(0, 0, 80, 35)] autorelease];
  view.backgroundColor = [UIColor clearColor];
  view.style = style;
  backButton.customView = view;


  self.navigationItem.leftBarButtonItem = backButton;
Andrew Arrow
Can you post a screenshot of the final result?
jm
it looked terrible. Never got the left arrow back button to look quite right. I gave up and used a proper back button with the Three20 navigator.
Andrew Arrow
A: 

If it's in UIKit, you'll find it with UIKit Artwork Extractor.

0xced
A: 
Cameron Palmer
+7  A: 

This can be done without adding in your own image files using sekr1t button type 101 to get the correct shape. For me the trick was figuring out that I could use 'initWithCustomView' to create the Bar Button Item. I personally needed this for a dynamic navbar rather than a toolbar, but I tested it with a toolbar and the code is nearly the same:

// create button
UIButton* backButton = [UIButton buttonWithType:101]; // left-pointing shape!
[backButton addTarget:self action:@selector(backAction) forControlEvents:UIControlEventTouchUpInside];
[backButton setTitle:@"Back" forState:UIControlStateNormal];

// create button item -- possible because UIButton subclasses UIView!
UIBarButtonItem* backItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];

// add to toolbar, or to a navbar (you should only have one of these!)
[toolbar setItems:[NSArray arrayWithObject:backItem]];
navItem.leftBarButtonItem = backItem;

If you're doing this on a toolbar you'll have to tweak how you set the items, but that depends on the rest of your code and I leave that as an exercise for the reader. :P This sample worked for me (compiled & run).

Blah blah, read the HIG, don't use undocumented features, and all that.

AndrewS
Nice! What is the number code for a forward pointing button?
MattDiPasquale
button type 101 doesn't seem to be giving me a left-pointing shape... just a rectangle.
elsurudo
A: 

I was trying to do the same thing, but I wanted the back button to be in the navigation bar. (I actually needed a back button, that would do more than only going back, so I had to use the leftBarButtonItem property). I tried what AndrewS suggested, but in the navigation bar it wouldn't look the way it should, as the UIButton was kind of casted to a UIBarButtonItem.

But I found a way to work around this. I actually just put a UIView unter the UIButton and set the customView for the UIBarButtonItem. Here is the code, if somebody needs it:

// initialize button and button view
UIButton* backButton = [UIButton buttonWithType:101];
UIView *backButtonView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, backButton.frame.size.width, backButton.frame.size.height)];

[backButton addTarget:self action:@selector(backButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
[backButton setTitle:@"Back" forState:UIControlStateNormal];
[backButtonView addSubview:backButton];

// set buttonview as custom view for bar button item
UIBarButtonItem* backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButtonView];
self.navigationItem.leftBarButtonItem = backButtonItem;

// push item to navigationbar items
[self.navigationController.navigationBar setItems:[NSArray arrayWithObject:backButtonItem]];
marikaner
A: 

I found that using the following, simple code did the trick (requires custom image in bundle):

// Creates a back button instead of default behaviour (displaying title of previous screen)
    UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"back_arrow.png"]
                                                                   style:UIBarButtonItemStyleBordered
                                                                  target:self
                                                                  action:@selector(backAction)];

    tipsDetailViewController.navigationItem.leftBarButtonItem = backButton;
    [backButton release];
maralbjo