[ios] UINavigationBar Hide back Button Text

How can I hide the Back Button Text from an UINavigation Controller? I will only have the "<" and not "< Back"

This question is related to ios uinavigationcontroller

The answer is


You can add this Objective-C category to make all "Back" buttons created by a navigation controller have no text. I just added it to my AppDelegate.m file.

@implementation UINavigationItem (Customization)

/**
 Removes text from all default back buttons so only the arrow or custom image shows up.
 */
-(UIBarButtonItem *)backBarButtonItem
{
    return [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
}

@end

PS - (I don't know how to make this extension work with Swift, it was having weird errors. Edits welcome to add a Swift version)


Swift 3.1 You can do this by implementing the delegate method of UINavigationController.

func navigationController(_ navigationController: UINavigationController, 
                          willShow viewController: UIViewController, animated: Bool) {

    /** It'll hide the Title with back button only,
     ** we'll still get the back arrow image and default functionality.
     */
    let item = UIBarButtonItem(title: " ", style: .plain, target: nil, 
                               action: nil)
    viewController.navigationItem.backBarButtonItem = item
}

Setting title of the back button to @"" or nil won't work. You need to set the entire button empty (without a title or image):

Objective-C

[self.navigationItem setBackBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil]];

Swift

self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)

This should be done on the view controller that's on top of your view controller in navigation stack (i.e. from where you navigate to your VC via pushViewController method)


The back text come from last View Controller's navigationItem.title,and navigationItem.title is automaticly set by self.title. So easy way to solve the problem is hook setTitle:,make sure navigationItem.title = @""

Put this code at AppDelegate.m will make it ok?

    [UIViewController aspect_hookSelector:@selector(setTitle:)
                              withOptions:AspectPositionAfter
                               usingBlock:^(id<AspectInfo> aspectInfo, NSString *title) {
        UIViewController *vc = aspectInfo.instance;
        vc.navigationItem.titleView = ({
            UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
            titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
            titleLabel.text = title;
            titleLabel;
        });
        vc.navigationItem.title = @"";
    } error:NULL];

More details at https://www.jianshu.com/p/071bc50f1475 (Simple Chinease)


I was struggling with this because I had a custom navigation controller. I was able to remove the back item text in all view controllers with this code in my custom navigation controller class override func viewDidLayoutSubviews() { self.navigationBar.backItem?.title = "" }

This removes all of the back item titles using this custom navigation controller.


A lot of answers already, here's my two cents on the subject. I found this approach really robust. You just need to put this in viewController before segue.

Swift 4:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
}

If you're targeting iOS 13 and later you can use this new API to hide the back button title globally.

let backButtonAppearance = UIBarButtonItemAppearance()
backButtonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.clear]

UINavigationBar.appearance().standardAppearance.backButtonAppearance = backButtonAppearance
UINavigationBar.appearance().compactAppearance.backButtonAppearance = backButtonAppearance
UINavigationBar.appearance().scrollEdgeAppearance.backButtonAppearance = backButtonAppearance

Another solution to this issue for situations where you have a great deal of view controllers is to use a UIAppearance proxy to effectively hide the back button title text like this:

UIBarButtonItem *navBarButtonAppearance = [UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], nil];

[navBarButtonAppearance setTitleTextAttributes:@{
    NSFontAttributeName:            [UIFont systemFontOfSize:0.1],
    NSForegroundColorAttributeName: [UIColor clearColor] }
                                      forState:UIControlStateNormal];

This solution will render the text as a tiny clear dot, similar to manually setting the back button title to @" ", except that it affects all nav bar buttons.

I don't suggest this as a general solution to the issue because it impacts all navigation bar buttons. It flips the paradigm so that you choose when to show the button titles, rather than when to hide the titles.

To choose when to show the titles, either manually restore the title text attributes as needed, or create a specialized subclass of UIBarButtonItem that does the same (potentially with another UIAppearance proxy).

If you have an app where most of the back button titles need to be hidden, and only a few (or none) of the nav buttons are system buttons with titles, this might be for you!

(Note: the font size change is needed even though the text color is clear in order to ensure that long titles do not cause the center nav bar title to shift over)


Swift version, works perfectly globally:

 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        UIBarButtonItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName:UIColor.clearColor()], forState: UIControlState.Normal)
        UIBarButtonItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName:UIColor.clearColor()], forState: UIControlState.Highlighted)

        return true
    }

The current answer wasn't working. I wanted to remove the title entirely, yet the text "back" wasn't going away.

Go back to the previous view controller and set its title property:

self.title = @" ";

ONLY works when the previous View Controller does not have a title


Alternative way - use custom NavigationBar class.

class NavigationBar: UINavigationBar {

    var hideBackItem = true
    private let emptyTitle = ""

    override func layoutSubviews() {
        if let `topItem` = topItem,
            topItem.backBarButtonItem?.title != emptyTitle,
            hideBackItem {
            topItem.backBarButtonItem = UIBarButtonItem(title: emptyTitle, style: .plain, target: nil, action: nil)
        }

        super.layoutSubviews()
    }

}

That is, this remove back titles whole project. Just set custom class for UINavigationController.


UINavigationControllerDelegate's navigationController(_, willShow:, animated:) method implementation did the trick for me.

Here goes the full view controller source code. if you want to apply this throughout the app, make all viewcontrollers to derive from BaseViewController.

class BaseViewController: UIViewController {
    // Controller Actions
    override func viewDidLoad() {
        super.viewDidLoad()
        navigationController?.delegate = self
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        updateNavigationBar()
    }
    
    //This is for custom back button image.
    func updateNavigationBar() {
        let imgBack = UIImage(named: "icon_back")
        self.navigationController?.navigationBar.backIndicatorImage = imgBack
        self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = imgBack
        self.navigationItem.backBarButtonItem = UIBarButtonItem()
    }
}

extension BaseViewController: UINavigationControllerDelegate {
    //This is to remove the "Back" text from back button.
    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
        viewController.navigationItem.backBarButtonItem = UIBarButtonItem()
    }
}

This is my resolution for iOS11, I change the appearance of UIBarButtonItem in applicationDidFinishLaunchingWithOptions :

UIBarButtonItem.appearance().setBackButtonTitlePositionAdjustment(UIOffsetMake(-100, 0), for:UIBarMetrics.default)

You can't change Y offset, because it will change the back bar button's position too in iOS11, but it's OK in iOS10 and below.


I tried some above and below but they didn't work. This worked for me:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationController?.navigationBar.topItem?.title = ""
}

The only thing which works with no side-effects is to create a custom back button. As long as you don't provide a custom action, even the slide gesture works.

extension UIViewController {
func setupBackButton() {
    let customBackButton = UIBarButtonItem(title: " ", style: .plain, target: nil, action: nil)
    navigationItem.backBarButtonItem = customBackButton
}}

Unfortunately, if you want all back buttons in the not to have any titles, you need to setup this custom back button in all your view controllers :/

override func viewDidLoad() {
    super.viewDidLoad()

    setupBackButton()
}

It is very important you set a whitespace as the title and not the empty string.


Finally found perfect solution to hide default back text in whole app.

Just add one transparent Image and add following code in your AppDelegate.

UIBarButtonItem.appearance().setBackButtonBackgroundImage(#imageLiteral(resourceName: "transparent"), for: .normal, barMetrics: .default)

I tried everything in this post. The only working solution is @VoidLess's

Here is the same answer but more complete

class CustomNavigationController: UINavigationController {

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.delegate = self
    }
}


// MARK:UINavigationControllerDelegate
extension CustomNavigationController {
    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
        viewController.navigationItem.backBarButtonItem = UIBarButtonItem(title: " ", style: .plain, target: nil, action: nil)
    }
}

The following method works on iOS 11 and is safe to not crash on other iOS versions. Doing this may get your app rejected in App Store review since both UIModernBarButton and UIBackButtonContainerView are private APIs. Place in AppDelegate.

    if
        let UIModernBarButton = NSClassFromString("_UIModernBarButton") as? UIButton.Type,
        let UIBackButtonContainerView = NSClassFromString("_UIBackButtonContainerView") as? UIView.Type {

        let backButton = UIModernBarButton.appearance(whenContainedInInstancesOf: [UIBackButtonContainerView.self])
        backButton.setTitleColor(.clear, for: .normal)
    }

-(void)setNavigationItems{
     UIBarButtonItem *leftBarButtonItem=[[UIBarButtonItem alloc]initWithTitle:@"**Your title here**" style:UIBarButtonItemStyleBordered target:self action:@selector(backButtonClicked)];   
     self.navigationController.navigationBar.topItem.backBarButtonItem=leftBarButtonItem;
}
-(void)backButtonClicked{
    [self.navigationController popViewControllerAnimated:YES];
}

XCode 11.5 Swift 5

A very simple - though perhaps a little hacky - way of doing programmatically this if you don't need the custom back button is to set the font size equal to zero in the view controller you're pushing onto the stack, calling something like this from viewDidLoad

private func setupNavBar() {
    let appearance = UINavigationBarAppearance()
    appearance.configureWithDefaultBackground()
    
    let backButtonAppearance = UIBarButtonItemAppearance()
    backButtonAppearance.normal.titleTextAttributes = [.font: UIFont(name: "Arial", size: 0)!]
    appearance.backButtonAppearance = backButtonAppearance

    navigationItem.standardAppearance = appearance
    navigationItem.scrollEdgeAppearance = appearance
    navigationItem.compactAppearance = appearance
}

For those who want to hide back button title globally.

You can swizzle viewDidLoad of UIViewController like this.

+ (void)overrideBackButtonTitle {

    NSError *error;

    // I use `Aspects` for easier swizzling.

    [UIViewController aspect_hookSelector:@selector(viewDidLoad)
                              withOptions:AspectPositionBefore
                               usingBlock:^(id<AspectInfo> aspectInfo)
    {

        UIViewController *vc = (UIViewController *)aspectInfo.instance;

        // Check whether this class is my app's view controller or not.
        // We don't want to override this for Apple's view controllers,
        // or view controllers from external framework.

        NSString *className = NSStringFromClass([vc class]);
        Class class = [NSBundle.mainBundle classNamed:className];
        if (!class) {
           return;
        }

        UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@" " style:UIBarButtonItemStylePlain target:nil action:nil];
        vc.navigationItem.backBarButtonItem = backButton;

    } error:&error];

    if (error) {
        NSLog(@"%s error: %@", __FUNCTION__, error.localizedDescription);
    }

}

Usage:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [[self class] overrideBackButtonTitle];
    return YES;
}

In Swift3,

If you set global setting

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    // ..

    let BarButtonItemAppearance = UIBarButtonItem.appearance()
    BarButtonItemAppearance.setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.clear], for: .normal)
    BarButtonItemAppearance.setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.clear], for: .highlighted)


    // ...

}

to remove the Text from backbutton programmatically, used below Code this will work form xcode7 and above.

self.navigationController.navigationBar.topItem.title = @" ";

or

manualLy in storyboards, select the navigation bar on the view controller and put " " in back button text.

this will work. thanks


Use a custom NavigationController that overrides pushViewController

class NavigationController: UINavigationController {  
  override func pushViewController(_ viewController: UIViewController, animated: Bool) {
    viewController.navigationItem.backBarButtonItem =
      UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
    super.pushViewController(viewController, animated: animated)
  }
}

This is from my xamarin.forms code, the class derives from NavigationRenderer

NavigationBar.Items.FirstOrDefault().BackBarButtonItem = new UIBarButtonItem( "", UIBarButtonItemStyle.Plain, null);

My solution: - XCode: 10.2.1 - Swift: 5

  • Parent viewcontroller:
    • self.title = ""
  • Child viewcontroller:
    • self.navigationItem.title = "Your title" // to set title for viewcontroller

In iOS 11, we found that setting UIBarButtonItem appearance's text font/color to a very small value or clear color will result other bar item to disappear (system does not honor the class of UIBarButton item anymore, it will convert it to a _UIModernBarButton). Also setting the offset of back text to offscreen will result flash during interactive pop.

So we swizzled addSubView:

+ (void)load {
    if (@available(iOS 11, *)) {
        [NSClassFromString(@"_UIBackButtonContainerView")     jr_swizzleMethod:@selector(addSubview:) withMethod:@selector(MyiOS11BackButtonNoTextTrick_addSubview:) error:nil];
    }
}

- (void)MyiOS11BackButtonNoTextTrick_addSubview:(UIView *)view {
    view.alpha = 0;
    if ([view isKindOfClass:[UIButton class]]) {
        UIButton *button = (id)view;
        [button setTitle:@" " forState:UIControlStateNormal];
    }
    [self MyiOS11BackButtonNoTextTrick_addSubview:view];
}

Set Title of the Previous VC to " " string with space. and title with the back button will be replaced with single space string.

Self.title = " "

On Back press again reset the title to original one in the viewWillAppear.


You can implement UINavigationControllerDelegate like this:

Older Swift

func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
    let item = UIBarButtonItem(title: " ", style: .Plain, target: nil, action: nil)
    viewController.navigationItem.backBarButtonItem = item
}

Swift 4.x

class MyNavigationController: UINavigationController, UINavigationControllerDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        self.delegate = self
    }

    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
        let item = UIBarButtonItem(title: " ", style: .plain, target: nil, action: nil)
        viewController.navigationItem.backBarButtonItem = item
    }
}

backBarButtonItem is nil by default and it affects next pushed controller, so you just set it for all controllers


Add the following code in viewDidLoad or loadView

self.navigationController.navigationBar.topItem.title = @"";  

I tested it in iPhone and iPad with iOS 9


You could also do this through storyboard. In the attribute inspector of the navigation item of the previous controller you could set " " in the Back button field. Refer Image below. Replace "Your Title here" to " ". By doing this you will achieve the desired result. You don't need to mess with the 'Title' anymore.

Programmatically you could use

[self.navigationItem.backBarButtonItem setTitle:@" "];

where self refers to the controller which pushes your desired View controller.

Xcode view controller navigation item

Sample Before, After Navigation bar

Before Before

After After