Remove back button text from inherited navigation bar Swift 3 - ios

I want to know if its possible to remove the navigation bar back button text from an inherited navigation bar. Presently my navigation bar shows "< ControllerName". I want to simply show the "<" back icon. I would also like to know how to show "< Back", and how to remove it completely.
I understand I could do this by adding a bar button item to the storyboard, however is there an easier way to do it?
Note, this code does not work:
self.navigationItem.backBarButtonItem = UIBarButtonItem(title:"", style:.plain, target:nil, action:nil)

You better custom back button for this task.
but You also can do it in other ways. Ex: You have ViewController1, and ViewController2 (You push ViewController2 from ViewController1)
ViewController1
public class ViewController1: UIViewController {
override public func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.title = "viewcontroller1 title"
}
}
ViewController2
class ViewController2: UIViewController {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// get previous view controller and set title to "" or any things You want
if let viewControllers = self.navigationController?.viewControllers {
let previousVC: UIViewController? = viewControllers.count >= 2 ? viewControllers[viewControllers.count - 2] : nil; // get previous view
previousVC?.title = "" // or previousVC?.title = "Back"
}
}
}

I think this will work for you.
self.navigationItem.hidesBackButton = true

Solution suggested by #Prashant will remove the back button from navigation bar.
To remove the title, use following:
navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)

Related

Swift how to preserve navigation bar button items after push

In my root view controller I set an array of bar button items with images and assign them to the right bar button.
When I push the next view controller my navigation bar resets and only displays a back button.
Any way to preserve the navigation bar as it was set on the root view controller so it will display on all pages?
As user1046037 has said you can set the item buttons while you are preparing the segue.
Example:
let helpViewController = HelpViewController(nibName: "HelpViewController", bundle: nil)
let someLeftButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.refresh, target: self, action: "someAction")
helpViewController.navigationItem.leftBarButtonItem = someLeftButton
helpViewController.navigationItem.leftItemsSupplementBackButton = true
navigationController?.pushViewController(helpViewController, animated: true)
This one is to preserve the left button item and the back one.
helpViewController.navigationItem.leftItemsSupplementBackButton = true
If you are going to use the same button in several Viewcontrollers you can create a BaseViewController setting up the button and his behaviors.
class AHBaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
configureNavigationBar()
// Configure Common status bar if you want too.
}
func configureNavigationBar() {
let someLeftButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.refresh, target: self, action: "someAction")
navigationItem.leftBarButtonItem = someLeftButton
navigationItem.leftItemsSupplementBackButton = true
}
}
Then just inherit it, in the viewControllers that you want to show the button(s).
class HelpViewController: AHBaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
When you segue between view controllers using Push, you're going to get the default "horizontal slide" navigation animation which. Try "present Modally" or "present as popover".

iOS: Removing UINavigationBar animation

Our app has an UINavigationBar with an image on it. When we segue (push) to another screen then click the back button the image on the Navigation Bar seems to animate from left to right as it reappears. This is a little distracting. How can you remove this back button animation?
We tried changing the segue Animates setting but this changes both the push animation and not the back animation.
Our Nav Bar code:
let logoImage:UIImage = UIImage(named: "ABC")!
viewController.navigationItem.titleView = UIImageView(image: logoImage)
Figured this out in large part due to this answer https://stackoverflow.com/a/8602982/47281
Create a custom Nav Bar and override popItem:
class MyNavigationBar: UINavigationBar {
override func popItem(animated: Bool) -> UINavigationItem? {
return super.popItem(animated: false)
}
}
Entered MyNavigationBar as the Navigation Bar class for our Navigation Controller via the Storyboard:
Note I did not override NavigationController popViewControllerAnimated as in the linked answer.
You can do this:
override func viewDidLoad() {
super.viewDidLoad()
let logoImage: UIImage = UIImage(named: "ABC")!
self.navigationItem.leftBarButtonItem = UIBarButtonItem(image: logoImage, style: .plain, target: self, action: #selector(backBtnPressed))
}
And then create a method to handle the tap on the button
func backBtnPressed(){
_ = self.navigationController?.popViewController(animated: false)
}

Can't get any navigation item in iOS

I have a question regarding the navigation bar.
As far as I understand from iOS: A view controller opened by a segue inherits the navigation bar of the parent view controller. Is this correct so far?
Is there a view controller within a stack "owns" the navigation bar in a complex segue stack (e.g. TableViewController that opens a TabBarController that opens ...)?
I very often run into the problem that I don't know where to get the actual navigation item in order to set the title or a bar button item.
In this case, I have the following controllers:
TabBarController
EventPostsViewController -> To display a list of posts, is a tabbed view within the TabBarController
CreatePostViewController -> To write a new post
So within the EventPostsViewController I can do this (and it works):
class EventPostsViewController: UITableViewController {
...
override func viewWillAppear(animated: Bool) {
...
// This solution works, but only for EventPostsViewController
self.tabBarController?.navigationItem.title = "text"
But within the CreatePostViewController, which is opened by a segue via EventPostsViewController, neither of this solutions work.
class CreatePostViewController: UIViewController {
...
override func viewWillAppear(animated: Bool) {
...
// Neither of these solutions works
self.navigationItem.title = "Text"
self.tabBarController?.navigationItem.title = "Text"
self.navigationController?.navigationItem.title = "Text"
How do I get the actual navigation bar/navigationItem?
Stupid simple mistake I repeat every time :)
I forgot to link my custom CreatePostViewController with the view controller using the interface builder.
This code now works:
class CreatePostViewController: UIViewController {
...
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated);
self.navigationController?.setNavigationBarHidden(false, animated: false)
// Set title
self.navigationItem.title = "Write Post"
// Add Submit button
var submitButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Done, target: self, action: "submitPost:")
self.navigationItem.rightBarButtonItem = submitButton
}
...
}

Swift Changing Navigation Bar in a ViewController

So here's my problem.
I added a empty ViewController to a NavigationController.
The problem is that when I add a View to the empty ViewController the navigation bar becomes unclickable I can't add back buttons or change the title.
I'm using Xcode 6.1 6A1052d.
You don't add buttons directly to navigation, but to the navigationItem of contained view controller. For example,
class ContainedViewController : UIViewController {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Add, target: nil, action: nil)
}
}

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"
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 = ""
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
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.
Sample Before, After Navigation bar
Before
After
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)
Add the following code in viewDidLoad or loadView
self.navigationController.navigationBar.topItem.title = #"";
I tested it in iPhone and iPad with iOS 9
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)
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 = ""
}
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)
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.
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
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
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
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.
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.
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)
}
Swift 5
viewController.navigationItem.backButtonDisplayMode = .minimal
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.
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)
}
}
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
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)
}
}
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.
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
}
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)
// ...
}
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;
}
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.
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)
}
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];
}
-(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];
}
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)
My solution:
- XCode: 10.2.1
- Swift: 5
Parent viewcontroller:
self.title = ""
Child viewcontroller:
self.navigationItem.title = "Your title" // to set title for viewcontroller
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
}

Resources