[ios] Creating a left-arrow button (like UINavigationBar's "back" style) on a UIToolbar

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.

This question is related to ios iphone cocoa-touch uinavigationbar uitoolbar

The answer is


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.


back arrow

If you don't want to bother with image files, the arrow shape can be drawn in a UIView subclass with the following code:

- (void)drawRect:(CGRect)rect {
    float width = rect.size.width;
    float height = rect.size.height;
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextBeginPath(context);
    CGContextMoveToPoint(context, width * 5.0/6.0, height * 0.0/10.0);
    CGContextAddLineToPoint(context, width * 0.0/6.0, height * 5.0/10.0);
    CGContextAddLineToPoint(context, width * 5.0/6.0, height * 10.0/10.0);
    CGContextAddLineToPoint(context, width * 6.0/6.0, height * 9.0/10.0);
    CGContextAddLineToPoint(context, width * 2.0/6.0, height * 5.0/10.0);
    CGContextAddLineToPoint(context, width * 6.0/6.0, height * 1.0/10.0);
    CGContextClosePath(context);

    CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
    CGContextFillPath(context);
}

where the arrow view is proportional to a width of 6.0 and a height of 10.0


Swift

// create button
    var backButton = UIButton(type: 101)

    // left-pointing shape!
    backButton.addTarget(self, action: #selector(self.backAction), for: .touchUpInside)
    backButton.setTitle("Back", for: .normal)

    // create button item -- possible because UIButton subclasses UIView!
    var backItem = UIBarButtonItem(customView: backButton)

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

WARNING: There are reports that this will not work on iOS 6. This might only work on older versions of the OS. Evidently at least one dev has had their app rejected for using this trick (see the comments). Use at your own risk. Using an image (see answer above) might be a safer solution.

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 BarButtonItem. 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. There's only six supported button types and this isn't one of them.


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


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.


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.


    self.navigationItem.leftBarButtonItem = self.navigationItem.backBarButtonItem;

Works for me. I used this when I had more tabs then could fit on the tab bar, and a view controller pushed from the "More" overrode the leftBarButtonItem in its viewDidLoad.


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];

I had a similar problem, and come out one library PButton. And the sample is the back navigation button like button, which can be used anywhere just like a customized button.

Something like this: enter image description here


Try this. I am sure you do not need a back button image to create one such.

UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Back"
                                                               style:UIBarButtonItemStyleBordered
                                                              target:self
                                                              action:@selector(yourSelectorGoesHere:)];
self.navigationItem.backBarButtonItem = backButton;

That's all you have to do :)


Example in Swift 3, with a previous and a next button in the top right.

let prevButtonItem = UIBarButtonItem(title: "\u{25C0}", style: .plain, target: self, action: #selector(prevButtonTapped))
let nextButtonItem = UIBarButtonItem(title: "\u{25B6}", style: .plain, target: self, action: #selector(nextButtonTapped))
self.navigationItem.rightBarButtonItems = [nextButtonItem, prevButtonItem]

Solution WITHOUT using a png. Based on this SO answer: Adding the little arrow to the right side of a cell in an iPhone TableView Cell

Just flipping the UITableViewCell horizontally!

UIButton *btnBack = [[UIButton alloc] initWithFrame:CGRectMake(0, 5, 70, 20)];

// Add the disclosure
CGRect frm;
UITableViewCell *disclosure = [[UITableViewCell alloc] init];
disclosure.transform = CGAffineTransformScale(CGAffineTransformIdentity, -1, 1);
frm = self.btnBack.bounds;
disclosure.frame = CGRectMake(frm.origin.x, frm.origin.y, frm.size.width-25, frm.size.height);
disclosure.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
disclosure.userInteractionEnabled = NO;
[self.btnBack addSubview:disclosure];

// Add the label
UILabel *lbl = [[UILabel alloc] init];
frm = CGRectOffset(self.btnBack.bounds, 15, 0);
lbl.frame = frm;
lbl.textAlignment = NSTextAlignmentCenter;
lbl.text = @"BACK";
[self addSubview:lbl];

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.


To make a UIButton with an arrow pretty close (I'm not a designer ;) to the iOS 7 system back arrow:

Standard:

Standard system back arrow

Apple SD Gothic Neo

Apple SD Gothic Neo < character

In Xcode:

  • Focus on the title value field of the button (or any other view/control with text content)
  • Open Edit -> Special Characters
  • Select the Parentheses group and double click the '<' character
  • Change font to: Apple SD Gothic Neo, Regular with desired size (e.g. 20)
  • Change colour as you like

Ref @staticVoidMan's answer to Back-like arrow on iOS 7


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.


Swift 5.2 Xcode 11.4

The Apple Symbol chevron.left now allows a more elegant solution to make a custom button. I have matched the size and spacing as close as possible.

enter image description here

import UIKit

class CustomBackButton: UIBarButtonItem {

    convenience init(target: Any, selector: Selector) {

        // Create UIButton
        let button = UIButton(frame: .zero)

        // Customise Title
        button.setTitle("Back", for: .normal)
        button.setTitleColor(.systemBlue, for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 17)

        // Customise Image
        let config = UIImage.SymbolConfiguration(pointSize: 19.0, weight: .semibold, scale: .large)
        let image = UIImage(systemName: "chevron.left", withConfiguration: config)
        button.setImage(image, for: .normal)

        // Add Target
        button.addTarget(target, action: selector, for: .touchUpInside)

        // Customise Spacing to match system Back button
        button.imageEdgeInsets = UIEdgeInsets(top: 0.0, left: -18.0, bottom: 0.0, right: 0.0)
        button.titleEdgeInsets = UIEdgeInsets(top: 0.0, left: -12.0, bottom: 0.0, right: 0.0)

        self.init(customView: button)
    }
}

This can be implemented either as a UIToolbarItem, or a UINavigationItem

override func viewDidLoad() {
    super.viewDidLoad()

    // UIToolbar Item
    let barBackButton = CustomBackButton(target: self, selector: #selector(backButtonTapped))
    let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
    navigationController?.setToolbarHidden(false, animated: false)
    toolbarItems = [barBackButton, flexSpace]

    // Navigation Item
    let navBackButton = CustomBackButton(target: self, selector: #selector(backButtonTapped))
    navigationItem.leftBarButtonItem = navBackButton
}

@objc func backButtonTapped() {
    print("Back tapped")
}

If you want to flip the button and have the arrow pointing to the Right:

enter image description here

Use Apple Symbol named "chevron.right"

Add the following code to the CustomBackButton class:

    // Put the image of the right side of the button
    button.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
    button.titleLabel?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
    button.imageView?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)

Swift

// create button
    var backButton = UIButton(type: 101)

    // left-pointing shape!
    backButton.addTarget(self, action: #selector(self.backAction), for: .touchUpInside)
    backButton.setTitle("Back", for: .normal)

    // create button item -- possible because UIButton subclasses UIView!
    var backItem = UIBarButtonItem(customView: backButton)

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

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 under 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]];

The Unicode Method

I think it is much easier to just use a unicode character to get the job done. You can look through arrows by googling either Unicode Triangles or Unicode Arrows. Starting with iOS6 Apple changed the character to be an emoji character with a border. To disable the border I add the 0xFE0E Unicode Variation Selector.

NSString *backArrowString = @"\U000025C0\U0000FE0E"; //BLACK LEFT-POINTING TRIANGLE PLUS VARIATION SELECTOR

UIBarButtonItem *backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:backArrowString style:UIBarButtonItemStylePlain target:nil action:nil];
self.navigationItem.leftButtonItem = backBarButtonItem;

The code block is just for the demo. It would work in any button that accepts an NSString.

For a full list of characters search Google for Unicode character and what you want. Here is the entry for Black Left-Pointing Triangle.

Result

The result


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];

The Unicode Method

I think it is much easier to just use a unicode character to get the job done. You can look through arrows by googling either Unicode Triangles or Unicode Arrows. Starting with iOS6 Apple changed the character to be an emoji character with a border. To disable the border I add the 0xFE0E Unicode Variation Selector.

NSString *backArrowString = @"\U000025C0\U0000FE0E"; //BLACK LEFT-POINTING TRIANGLE PLUS VARIATION SELECTOR

UIBarButtonItem *backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:backArrowString style:UIBarButtonItemStylePlain target:nil action:nil];
self.navigationItem.leftButtonItem = backBarButtonItem;

The code block is just for the demo. It would work in any button that accepts an NSString.

For a full list of characters search Google for Unicode character and what you want. Here is the entry for Black Left-Pointing Triangle.

Result

The result


I had a similar problem, and come out one library PButton. And the sample is the back navigation button like button, which can be used anywhere just like a customized button.

Something like this: enter image description here


To make a UIButton with an arrow pretty close (I'm not a designer ;) to the iOS 7 system back arrow:

Standard:

Standard system back arrow

Apple SD Gothic Neo

Apple SD Gothic Neo < character

In Xcode:

  • Focus on the title value field of the button (or any other view/control with text content)
  • Open Edit -> Special Characters
  • Select the Parentheses group and double click the '<' character
  • Change font to: Apple SD Gothic Neo, Regular with desired size (e.g. 20)
  • Change colour as you like

Ref @staticVoidMan's answer to Back-like arrow on iOS 7


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.


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.


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


Here's what I ended up doing after searching through all these solutions and others. It uses a stretchable png's extracted from the UIKit stock images. This way you can set the text to whatever you liek

// Generate the background images
UIImage *stretchableBackButton = [[UIImage imageNamed:@"UINavigationBarDefaultBack.png"] stretchableImageWithLeftCapWidth:14 topCapHeight:0];
UIImage *stretchableBackButtonPressed = [[UIImage imageNamed:@"UINavigationBarDefaultBackPressed.png"] stretchableImageWithLeftCapWidth:13 topCapHeight:0];
// Setup the UIButton
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[backButton setBackgroundImage:stretchableBackButton forState:UIControlStateNormal];
[backButton setBackgroundImage:stretchableBackButtonPressed forState:UIControlStateSelected];
NSString *buttonTitle = NSLocalizedString(@"Back", @"Back");
[backButton setTitle:buttonTitle forState:UIControlStateNormal];
[backButton setTitle:buttonTitle forState:UIControlStateSelected];
backButton.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 2, 1); // Tweak the text position
NSInteger width = ([backButton.titleLabel.text sizeWithFont:backButton.titleLabel.font].width + backButton.titleEdgeInsets.right +backButton.titleEdgeInsets.left);
[backButton setFrame:CGRectMake(0, 0, width, 29)];
backButton.titleLabel.font = [UIFont boldSystemFontOfSize:13.0f];
[backButton addTarget:self action:@selector(yourSelector:) forControlEvents:UIControlEventTouchDown];
// Now add the button as a custom UIBarButtonItem
UIBarButtonItem *backButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:backButton] autorelease];
self.navigationItem.leftBarButtonItem = backButtonItem;

It's easy to do with Interface Builder in Xcode 5.x

Result

  • use Toolbar and Bar Button Item from Object library

    Components

  • in button's Attributes inspector edit Image section with your back button image

    Attributes inspector

Done!


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.


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


It's easy to do with Interface Builder in Xcode 5.x

Result

  • use Toolbar and Bar Button Item from Object library

    Components

  • in button's Attributes inspector edit Image section with your back button image

    Attributes inspector

Done!


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.


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;

back arrow

If you don't want to bother with image files, the arrow shape can be drawn in a UIView subclass with the following code:

- (void)drawRect:(CGRect)rect {
    float width = rect.size.width;
    float height = rect.size.height;
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextBeginPath(context);
    CGContextMoveToPoint(context, width * 5.0/6.0, height * 0.0/10.0);
    CGContextAddLineToPoint(context, width * 0.0/6.0, height * 5.0/10.0);
    CGContextAddLineToPoint(context, width * 5.0/6.0, height * 10.0/10.0);
    CGContextAddLineToPoint(context, width * 6.0/6.0, height * 9.0/10.0);
    CGContextAddLineToPoint(context, width * 2.0/6.0, height * 5.0/10.0);
    CGContextAddLineToPoint(context, width * 6.0/6.0, height * 1.0/10.0);
    CGContextClosePath(context);

    CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
    CGContextFillPath(context);
}

where the arrow view is proportional to a width of 6.0 and a height of 10.0


WARNING: There are reports that this will not work on iOS 6. This might only work on older versions of the OS. Evidently at least one dev has had their app rejected for using this trick (see the comments). Use at your own risk. Using an image (see answer above) might be a safer solution.

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 BarButtonItem. 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. There's only six supported button types and this isn't one of them.


    self.navigationItem.leftBarButtonItem = self.navigationItem.backBarButtonItem;

Works for me. I used this when I had more tabs then could fit on the tab bar, and a view controller pushed from the "More" overrode the leftBarButtonItem in its viewDidLoad.


Here's what I ended up doing after searching through all these solutions and others. It uses a stretchable png's extracted from the UIKit stock images. This way you can set the text to whatever you liek

// Generate the background images
UIImage *stretchableBackButton = [[UIImage imageNamed:@"UINavigationBarDefaultBack.png"] stretchableImageWithLeftCapWidth:14 topCapHeight:0];
UIImage *stretchableBackButtonPressed = [[UIImage imageNamed:@"UINavigationBarDefaultBackPressed.png"] stretchableImageWithLeftCapWidth:13 topCapHeight:0];
// Setup the UIButton
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[backButton setBackgroundImage:stretchableBackButton forState:UIControlStateNormal];
[backButton setBackgroundImage:stretchableBackButtonPressed forState:UIControlStateSelected];
NSString *buttonTitle = NSLocalizedString(@"Back", @"Back");
[backButton setTitle:buttonTitle forState:UIControlStateNormal];
[backButton setTitle:buttonTitle forState:UIControlStateSelected];
backButton.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 2, 1); // Tweak the text position
NSInteger width = ([backButton.titleLabel.text sizeWithFont:backButton.titleLabel.font].width + backButton.titleEdgeInsets.right +backButton.titleEdgeInsets.left);
[backButton setFrame:CGRectMake(0, 0, width, 29)];
backButton.titleLabel.font = [UIFont boldSystemFontOfSize:13.0f];
[backButton addTarget:self action:@selector(yourSelector:) forControlEvents:UIControlEventTouchDown];
// Now add the button as a custom UIBarButtonItem
UIBarButtonItem *backButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:backButton] autorelease];
self.navigationItem.leftBarButtonItem = backButtonItem;

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 under 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]];

enter image description here

First of all you have to find an image of the back button. I used a nice app called Extractor that extracts all the graphics from iPhone. In iOS7 I managed to retrieve the image called UINavigationBarBackIndicatorDefault and it was in black colour, since I needed a red tint I change the colour to red using Gimp.

EDIT:

As was mentioned by btate in his comment, there is no need to change the color with the image editor. The following code should do the trick:

imageView.tint = [UIColor redColor];
imageView.image = [[UIImage imageNamed:@"UINavigationBarBackIndicatorDefault"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];

Then I created a view that contains an imageView with that arrow, a label with the custom text and on top of the view I have a button with an action. Then I added a simple animation (fading and translation).

The following code simulates the behaviour of the back button including animation.

-(void)viewWillAppear:(BOOL)animated{
        UIImageView *imageView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"UINavigationBarBackIndicatorDefault"]];
        [imageView setTintColor:[UIColor redColor]];
        UILabel *label=[[UILabel alloc] init];
        [label setTextColor:[UIColor redColor]];
        [label setText:@"Blog"];
        [label sizeToFit];

        int space=6;
        label.frame=CGRectMake(imageView.frame.origin.x+imageView.frame.size.width+space, label.frame.origin.y, label.frame.size.width, label.frame.size.height);
        UIView *view=[[UIView alloc] initWithFrame:CGRectMake(0, 0, label.frame.size.width+imageView.frame.size.width+space, imageView.frame.size.height)];

        view.bounds=CGRectMake(view.bounds.origin.x+8, view.bounds.origin.y-1, view.bounds.size.width, view.bounds.size.height);
        [view addSubview:imageView];
        [view addSubview:label];

        UIButton *button=[[UIButton alloc] initWithFrame:view.frame];
        [button addTarget:self action:@selector(handleBack:) forControlEvents:UIControlEventTouchUpInside];
        [view addSubview:button];

        [UIView animateWithDuration:0.33 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
            label.alpha = 0.0;
            CGRect orig=label.frame;
            label.frame=CGRectMake(label.frame.origin.x+25, label.frame.origin.y, label.frame.size.width, label.frame.size.height);
            label.alpha = 1.0;
            label.frame=orig;
        } completion:nil];

        UIBarButtonItem *backButton =[[UIBarButtonItem alloc] initWithCustomView:view];
}

- (void) handleBack:(id)sender{
}

EDIT:

Instead of adding the button, in my opinion the better approach is to use a gesture recognizer.

UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleBack:)];
[view addGestureRecognizer:tap];
[view setUserInteractionEnabled:YES];

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.


enter image description here

First of all you have to find an image of the back button. I used a nice app called Extractor that extracts all the graphics from iPhone. In iOS7 I managed to retrieve the image called UINavigationBarBackIndicatorDefault and it was in black colour, since I needed a red tint I change the colour to red using Gimp.

EDIT:

As was mentioned by btate in his comment, there is no need to change the color with the image editor. The following code should do the trick:

imageView.tint = [UIColor redColor];
imageView.image = [[UIImage imageNamed:@"UINavigationBarBackIndicatorDefault"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];

Then I created a view that contains an imageView with that arrow, a label with the custom text and on top of the view I have a button with an action. Then I added a simple animation (fading and translation).

The following code simulates the behaviour of the back button including animation.

-(void)viewWillAppear:(BOOL)animated{
        UIImageView *imageView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"UINavigationBarBackIndicatorDefault"]];
        [imageView setTintColor:[UIColor redColor]];
        UILabel *label=[[UILabel alloc] init];
        [label setTextColor:[UIColor redColor]];
        [label setText:@"Blog"];
        [label sizeToFit];

        int space=6;
        label.frame=CGRectMake(imageView.frame.origin.x+imageView.frame.size.width+space, label.frame.origin.y, label.frame.size.width, label.frame.size.height);
        UIView *view=[[UIView alloc] initWithFrame:CGRectMake(0, 0, label.frame.size.width+imageView.frame.size.width+space, imageView.frame.size.height)];

        view.bounds=CGRectMake(view.bounds.origin.x+8, view.bounds.origin.y-1, view.bounds.size.width, view.bounds.size.height);
        [view addSubview:imageView];
        [view addSubview:label];

        UIButton *button=[[UIButton alloc] initWithFrame:view.frame];
        [button addTarget:self action:@selector(handleBack:) forControlEvents:UIControlEventTouchUpInside];
        [view addSubview:button];

        [UIView animateWithDuration:0.33 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
            label.alpha = 0.0;
            CGRect orig=label.frame;
            label.frame=CGRectMake(label.frame.origin.x+25, label.frame.origin.y, label.frame.size.width, label.frame.size.height);
            label.alpha = 1.0;
            label.frame=orig;
        } completion:nil];

        UIBarButtonItem *backButton =[[UIBarButtonItem alloc] initWithCustomView:view];
}

- (void) handleBack:(id)sender{
}

EDIT:

Instead of adding the button, in my opinion the better approach is to use a gesture recognizer.

UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleBack:)];
[view addGestureRecognizer:tap];
[view setUserInteractionEnabled:YES];

Swift 5.2 Xcode 11.4

The Apple Symbol chevron.left now allows a more elegant solution to make a custom button. I have matched the size and spacing as close as possible.

enter image description here

import UIKit

class CustomBackButton: UIBarButtonItem {

    convenience init(target: Any, selector: Selector) {

        // Create UIButton
        let button = UIButton(frame: .zero)

        // Customise Title
        button.setTitle("Back", for: .normal)
        button.setTitleColor(.systemBlue, for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 17)

        // Customise Image
        let config = UIImage.SymbolConfiguration(pointSize: 19.0, weight: .semibold, scale: .large)
        let image = UIImage(systemName: "chevron.left", withConfiguration: config)
        button.setImage(image, for: .normal)

        // Add Target
        button.addTarget(target, action: selector, for: .touchUpInside)

        // Customise Spacing to match system Back button
        button.imageEdgeInsets = UIEdgeInsets(top: 0.0, left: -18.0, bottom: 0.0, right: 0.0)
        button.titleEdgeInsets = UIEdgeInsets(top: 0.0, left: -12.0, bottom: 0.0, right: 0.0)

        self.init(customView: button)
    }
}

This can be implemented either as a UIToolbarItem, or a UINavigationItem

override func viewDidLoad() {
    super.viewDidLoad()

    // UIToolbar Item
    let barBackButton = CustomBackButton(target: self, selector: #selector(backButtonTapped))
    let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
    navigationController?.setToolbarHidden(false, animated: false)
    toolbarItems = [barBackButton, flexSpace]

    // Navigation Item
    let navBackButton = CustomBackButton(target: self, selector: #selector(backButtonTapped))
    navigationItem.leftBarButtonItem = navBackButton
}

@objc func backButtonTapped() {
    print("Back tapped")
}

If you want to flip the button and have the arrow pointing to the Right:

enter image description here

Use Apple Symbol named "chevron.right"

Add the following code to the CustomBackButton class:

    // Put the image of the right side of the button
    button.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
    button.titleLabel?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
    button.imageView?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)

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;

Try this. I am sure you do not need a back button image to create one such.

UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Back"
                                                               style:UIBarButtonItemStyleBordered
                                                              target:self
                                                              action:@selector(yourSelectorGoesHere:)];
self.navigationItem.backBarButtonItem = backButton;

That's all you have to do :)


Solution WITHOUT using a png. Based on this SO answer: Adding the little arrow to the right side of a cell in an iPhone TableView Cell

Just flipping the UITableViewCell horizontally!

UIButton *btnBack = [[UIButton alloc] initWithFrame:CGRectMake(0, 5, 70, 20)];

// Add the disclosure
CGRect frm;
UITableViewCell *disclosure = [[UITableViewCell alloc] init];
disclosure.transform = CGAffineTransformScale(CGAffineTransformIdentity, -1, 1);
frm = self.btnBack.bounds;
disclosure.frame = CGRectMake(frm.origin.x, frm.origin.y, frm.size.width-25, frm.size.height);
disclosure.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
disclosure.userInteractionEnabled = NO;
[self.btnBack addSubview:disclosure];

// Add the label
UILabel *lbl = [[UILabel alloc] init];
frm = CGRectOffset(self.btnBack.bounds, 15, 0);
lbl.frame = frm;
lbl.textAlignment = NSTextAlignmentCenter;
lbl.text = @"BACK";
[self addSubview:lbl];

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


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.


Example in Swift 3, with a previous and a next button in the top right.

let prevButtonItem = UIBarButtonItem(title: "\u{25C0}", style: .plain, target: self, action: #selector(prevButtonTapped))
let nextButtonItem = UIBarButtonItem(title: "\u{25B6}", style: .plain, target: self, action: #selector(nextButtonTapped))
self.navigationItem.rightBarButtonItems = [nextButtonItem, prevButtonItem]

Examples related to ios

Adding a UISegmentedControl to UITableView Crop image to specified size and picture location Undefined Symbols error when integrating Apptentive iOS SDK via Cocoapods Keep placeholder text in UITextField on input in IOS Accessing AppDelegate from framework? Autoresize View When SubViews are Added Warp \ bend effect on a UIView? Speech input for visually impaired users without the need to tap the screen make UITableViewCell selectable only while editing Xcode 12, building for iOS Simulator, but linking in object file built for iOS, for architecture arm64

Examples related to iphone

Detect if the device is iPhone X Xcode 8 shows error that provisioning profile doesn't include signing certificate Access files in /var/mobile/Containers/Data/Application without jailbreaking iPhone Certificate has either expired or has been revoked Missing Compliance in Status when I add built for internal testing in Test Flight.How to solve? cordova run with ios error .. Error code 65 for command: xcodebuild with args: "Could not find Developer Disk Image" Reason: no suitable image found iPad Multitasking support requires these orientations How to insert new cell into UITableView in Swift

Examples related to cocoa-touch

Include of non-modular header inside framework module Move textfield when keyboard appears swift Create space at the beginning of a UITextField Navigation bar with UIImage for title Generate a UUID on iOS from Swift How do I write a custom init for a UIView subclass in Swift? creating custom tableview cells in swift How would I create a UIAlertView in Swift? Get current NSDate in timestamp format How do you add an in-app purchase to an iOS application?

Examples related to uinavigationbar

Swift programmatically navigate to another view controller/scene How to enable back/left swipe gesture in UINavigationController after setting leftBarButtonItem? How to hide a navigation bar from first ViewController in Swift? Change color of Back button in navigation bar NavigationBar bar, tint, and title text color in iOS 8 transparent navigation bar ios presenting ViewController with NavigationViewController swift Changing navigation title programmatically Navigation bar with UIImage for title Changing navigation bar color in Swift

Examples related to uitoolbar

How do I show/hide a UIBarButtonItem? Creating a left-arrow button (like UINavigationBar's "back" style) on a UIToolbar