Nils
Nils

Reputation: 1507

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"

Upvotes: 128

Views: 131068

Answers (30)

Amrit Giri
Amrit Giri

Reputation: 737

if #available(iOS 13.0, *) {
            let appearance = UINavigationBarAppearance()
            appearance.backButtonAppearance.normal.titlePositionAdjustment = UIOffset.init(horizontal: -300.0, vertical: 0.0)
}else{
      let barButtonApperance = UIBarButtonItem.appearance()
barButtonApperance.setTitleTextAttributes([NSAttributedString.Key.foregroundColor:AppColor.PrimaryGray.value], for: UIControl.State.normal)

}

Upvotes: 2

jday
jday

Reputation: 578

In iOS 15, I could only get the back button text to disappear using the bar appearance API. It seems like overkill, but I've ended up reusing this all over an app. Here's an extension with a bunch of other useful pieces to customize a nav bar. Setting backButtonTextColor to .clear does the trick for this particular issue.

extension UIViewController {
    @objc func setNavBarAppearance(with backgroundColor: UIColor,
                                   titleColor: UIColor? = nil,
                                   shadowColor: UIColor? = nil,
                                   tintColor: UIColor? = nil,
                                   backButtonTextColor: UIColor? = nil) {
        let appearance = UINavigationBarAppearance()
        appearance.configureWithOpaqueBackground()
        appearance.backgroundColor = backgroundColor
    
        if let titleColor = titleColor {
            appearance.titleTextAttributes = [.foregroundColor: titleColor]
        }

        if let shadowColor = shadowColor {
            appearance.shadowColor = shadowColor
        }

        if let tintColor = tintColor {
            navigationController?.navigationBar.tintColor = tintColor
        }
    
        if let backButtonTextColor = backButtonTextColor {
            let backButtonAppearance = UIBarButtonItemAppearance()
            backButtonAppearance.normal.titleTextAttributes = [.foregroundColor: backButtonTextColor]
            appearance.backButtonAppearance = backButtonAppearance
        }

        navigationController?.navigationBar.standardAppearance = appearance
        navigationController?.navigationBar.scrollEdgeAppearance = appearance
    }
}

Call it in your view controller's viewDidLoad like:

setNavBarAppearance(with: .systemBackground, backButtonTextColor: .clear)

Upvotes: 0

Angel G. Olloqui
Angel G. Olloqui

Reputation: 8105

The problem with most solutions here is that setting an empty text on the back item does not work well with the new functionality for long press on back buttons. Instead of showing proper titles, it is just showing an empty list

Empty list on long pressing a back button

Instead, you can use the new button display mode for iOS14 or rely on the new appearance APIs for iOS13 , to set the text to size 0. Note that some people are playing with the color (clear), that doesnt work well either because it uses the space and removes it from your titles. If the title is long enough, you will see it clipped

Resulting code:

public extension UINavigationBar {
    func fixAppearance() {
        if #available(iOS 14.0, *) {
            topItem?.backButtonDisplayMode = .minimal
        } else if #available(iOS 13.0, *) {
            let newAppearance = standardAppearance.copy()
            newAppearance.backButtonAppearance.normal.titleTextAttributes = [
                .foregroundColor: UIColor.clear,
                .font: UIFont.systemFont(ofSize: 0)
            ]
            standardAppearance = newAppearance
        } else {
            topItem?.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
        }
    }
}

Then you just need to call that method when view controllers are presented, so either you call it from a base class (on viewWillAppear for example) or you add some delegate to the navigation controller like in other answers of this post.

Upvotes: 6

elliot
elliot

Reputation: 149

Swift 5

viewController.navigationItem.backButtonDisplayMode = .minimal

Upvotes: 7

Li Jin
Li Jin

Reputation: 2147

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()
    }
}

Upvotes: 0

Pakchoiandbacon
Pakchoiandbacon

Reputation: 55

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
}

Upvotes: 0

heyfrank
heyfrank

Reputation: 5647

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

Upvotes: 4

Martin
Martin

Reputation: 4765

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 = ""
}

Upvotes: 25

PhuocLuong
PhuocLuong

Reputation: 739

My solution: - XCode: 10.2.1 - Swift: 5

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

Upvotes: 0

fengxing
fengxing

Reputation: 474

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)

Upvotes: 0

Ilya
Ilya

Reputation: 1460

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

Upvotes: 94

jackal
jackal

Reputation: 1219

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)

Upvotes: 56

Codetard
Codetard

Reputation: 2595

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)
}

Upvotes: 5

niku
niku

Reputation: 492

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

Upvotes: 0

Amy.R
Amy.R

Reputation: 11

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.

Upvotes: 1

Patrick
Patrick

Reputation: 2382

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)
    }

Upvotes: -2

nRewik
nRewik

Reputation: 9148

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

Upvotes: 2

Kumar
Kumar

Reputation: 1942

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)

Upvotes: -1

S.M.Moinuddin
S.M.Moinuddin

Reputation: 333

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
}

Upvotes: 3

LLIAJLbHOu
LLIAJLbHOu

Reputation: 1313

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.

Upvotes: 5

VictorChee
VictorChee

Reputation: 339

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.

Upvotes: 3

onmyway133
onmyway133

Reputation: 48085

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)
  }
}

Upvotes: 4

sbhhbs
sbhhbs

Reputation: 625

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

Upvotes: 0

Christos Chadjikyriacou
Christos Chadjikyriacou

Reputation: 3749

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)
    }
}

Upvotes: 3

taku_oka
taku_oka

Reputation: 453

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)


    // ...

}

Upvotes: 2

Cezar Signori
Cezar Signori

Reputation: 596

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.

Upvotes: 14

Mohit Kumar
Mohit Kumar

Reputation: 3086

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.

Upvotes: 4

rebello95
rebello95

Reputation: 8576

In the interface builder, you can select the navigation item of the previous controller and change the Back Button string to what you'd like the back button to appear as. If you want it blank, for example, just put a space.

You can also change it with this line of code:

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

Or in Swift:

self.navigationItem.backBarButtonItem?.title = ""

Upvotes: 124

Jyothi Babu Pakalz
Jyothi Babu Pakalz

Reputation: 107

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

Upvotes: 9

Pinkladyla
Pinkladyla

Reputation: 44

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

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

Upvotes: -5

Related Questions