This is my first day trying to write an iOS app, having followed the tutorials on the Apple site and a few others, so be gentle. It's actually going pretty well so far!
My main view is a list of company contacts. Tapping on a contact segues to a view showing that contact's details. I've embedded my views in a Navigation view, and the navigation all works fine. On the contact details view, the view title (self.title) is being set to the person's name in the viewDidLoad function.
The problem I've got is that the text of the 'back' navigation button in the title bar on the contact details view is being derived from the title of the main view, as expected, but that text is long enough to push the title of the contact detail view - the person's name - to the right, like this:
I was wondering if this is the expected and correct behaviour for an iOS app or if I should attempt to have the contact detail view's title displayed on a different line to the back navigation button, and, if so, how I would do that.
I know that I can override the text of the back navigation button (indeed, it's automatically set to "Back" if my main controller's title is set to something a bit longer, interestingly), but that's not going to solve the problem if a person has a particularly long name!
What you're seeing is indeed the correct/expected behavior.
If you don't like that back button text, you can always change or remove it:
let backButtonItem: UIBarButtonItem = UIBarButtonItem()
backButtonItem.title = "" // Set your custom text here
navigationItem.backBarButtonItem = backButtonItem
If you want to do a multi-line title you'll have to customize it by either creating your own UINavigationBar subclass or by setting a custom titleView on your UINavigationItem and setting a custom view in which you render multiple lines.
Related
I need to implement the navigation bar with custom back image and custom title. For example: if i am in "Login with facebook" page i need to show the "Login with facebook" besides the custom back image. For this i am following the code like this:
let yourBackImage = UIImage(named: "back_button_image")
self.navigationController?.navigationBar.backIndicatorImage = yourBackImage
self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = yourBackImage
self.navigationController?.navigationBar.backItem?.title = "Custom"
But I am getting the output like this:
Note: The title is of the current page.
How to achieve this?
If the back title is too long iOS will change it to 'Back'.
However if you add a left bar button item - this you can set to a longer length.
long back
From Apple docs: https://developer.apple.com/documentation/uikit/uinavigationcontroller
In cases where the title of a back button is too long to fit in the available space, the navigation bar may substitute the string “Back” for the actual button title. The navigation bar does this only if the back button is provided by the previous view controller. If the new top-level view controller has a custom left bar button item—an object in the
leftBarButtonItem
or
leftBarButtonItems
property of its navigation item—the navigation bar does not change the button title.
To do this go to the Storyboard, in Interface Builder, drag a Bar Button Item into your navigation bar and set its title.
*Note that you will need to hook this up to your view controller to pop it.
#IBAction func pop(_ sender: UIBarButtonItem) {
_ = navigationController?.popViewController(animated: true)
}
You'll find a lot of StackOverflow attempts to answer this (quite common) issue, and the best way that I've found is also rather complicated. You'll have to do this for every UINavigationController, UINavigationBar, and UINavigationItem in your app, and that's painful.
How Apple wants you to do it (as far as I can tell)
For UINavigationBars in a storyboard, set the Back and Back Mask values (in the Attributes inspector) to the name of your custom image.
For every view controller's UINavigationItem, set its Back attribute value to an empty string or single space.
Easy enough, right? Nope. For one thing, the empty string or single-space Back title isn't always honored. And what if you have dozens, or even hundreds, of view controllers? What if your application has multiple UINavigationControllers? What if you set configure your view controllers (or at least their navigation items) programmatically? Then it's not so easy.
How StackOverflow thinks you should do it
I'm not going to link to all of the SO answers that recommend this way of doing things. I'll just summarize it as:
Hide the navigation item's back button with UINavigationItem.setHidesBackBarItem(_:animated:).
Create a UIBarButtonItem with your custom back image and empty title, then add it to your navigation item's leftBarButtonItem.
Sit back and wait for user bug reports to flood in with complaints that your app doesn't support swiping to navigate back.
Or, if you want to be clever, attach your navigation controller's interactivePopGestureRecognizer to your custom left bar button item. This usually works, but it feels like a hack that's likely to break in future releases. If you're ok with that, then you can stop reading right here.
How I think you should do it
If you have a lot of view controllers (our app has 200+) and/or a mix of VCs configured programmatically and in storyboards, this may ultimately be an easier way.
Create a subclass of UINavigationBar and set this as the class for all navigation bars in your storyboards and code. (If you're doing it in code, note that the nav bar is a read-only property; it can be set only in the navigation controller's initializer.)
The UINavigationBar manages a stack of UINavigationItems, one for each view controller on the UINavigationController's stack, and keeps them in sync with their view controllers. In other words, when you push a view controller onto the nav controller, that view controller's nav item also gets pushed onto the nav bar, and it gets popped when the VC is popped. When the navigation bar pushes or pops an item, it uses the new topmost item's title, titleView, and/or button item properties to set configure its own title view and buttons, and uses the title of the navigation item immediately below the topmost one to configure its back button and back image. If the next-to-topmost item's title is nil, then the nav bar uses the default value of "Back". You don't want that. If you can set the Back attribute to an empty or single-space string in the storyboard, then you should be able to do the same thing in code, right? Wrong. The back text is not a public property in UINavigationItem! WTF?
Instead, you have to set the title of the next-to-topmost item to an empty string. "But wait!" you say, "Doesn't that permanently change the next-to-topmost item's title, so that when I navigate back to that view controller, its title will say "Back" instead of its original title?" And you'd be right. What can you do? In your subclass of UINavigationBar, add an array of Optional title strings, like so:
var navigationItemTitles = [String?]()
(Why Optional? Because navigation items may have a custom titleView instead of a title.)
Override the navigation bar's pushNavigationItem(_:animated:) and popNavigationItemAnimated(_:) so that they modify and restore the navigation items' titles, respectively:
override func pushNavigationItem(_ item: UINavigationItem, animated: Bool) {
super.pushNavigationItem(item, animated: animated)
// Store the new back item's title, then set its title to
// an empty string.
if let backItem = backItem {
navigationItemTitles.push(backItem.title)
backItem.title = ""
}
}
override func popNavigationItemAnimated(_ animated: Bool) {
super.popNavigationItemAnimated(animated)
// Restore the new top item's title.
if navigationItemTitles.count > 0 {
topItem?.title = navigationItemTitles.popLast
}
}
Caveats
This is the only way I've found that's foolproof and not hacky. If Apple simply made the navigation item's Back property publicly settable, then a lot of this could be avoided.
(For what its worth, not only does our app have 200+ view controllers, it also has multiple navigation controllers with different navigation bar looks and feels. That's a whole other layer of complexity.)
I'm modifying an app and this app has some buttons in its navigation bar, I wanted to add another button or Bar Button item by dragging it to the hierarchy but it seems I can't add it as a child to navigation bar, I wanted to ask if you have any solutions to this, here's a snapshot of the hierarchy of the storyboard, I want to add another Bar Button Item or another Button to the Navigation item.
Thanks
So I've just created a blank project and I can do this:
I've also done stuff like this before where I actually use a UIButton rather than a bar button item gaining some extra customisability. Just make sure that you set an outlet to the button and in the view controller call self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:self.customButton];:
You can have multiple right bar button items and if they overlap the title (if you have one) then they are essentially clipped. From my understanding, you can have as many buttons as you like until the space is gone (which can vary depending on the device, obviously). Relevant docs:
This array can contain 0 or more bar button items to display on the right side of the
navigation bar. Items are displayed right-to-left in the same order as they appear in the array. Thus, the first item in the array is the rightmost item and other items are added to the left of the previous item.
If there is not enough room to display all of the items in the array, those that would overlap the title view (if present) or the buttons on the left side of the bar are not
displayed.
An example with lots of buttons:
Programatically you can add buttons using:
navigationItem.rightBarButtonItems = [aButton, anotherButton, awesomeButton]
Just make sure you test that the smallest device you target will still provide a good UX for the user if you add lots of buttons.
here is the correct answer for swift :
let barButton_array: [UIBarButtonItem] = [Button1, Button2]
navigationItem.setRightBarButtonItems(barButton_array, animated: false)
Seems you can only have 3 elements on navigation bar with Interface Builder and you have to add more buttons via code. This link worked for me :
http://mandarapte.com/apple/add-navigation-bar-buttons-ios-app-xcode-project/
Seemingly the accepted way of changing the back button text for a UIViewController's navigation bar is this answer, essentially setting the text to nothing on the previous view controller.
However, this has to be done on every view controller. Worse yet, the button still takes up quite a bit of horizontal space (past what you would logically expect) as if there's still text there.
Is there a way, say in a UINavigationController subclass to hide the back button text in every view controller and make the area occupied by the back button more or less just the size of the "<"?
Create a subclass of UINavigationBar. In your subclass, override backItem to return a UINavigationItem with an empty title. You might have to use a string containing a space rather than the empty string.
Specify that subclass as the custom class of the navigation bar in your storyboard, or (if you create the navigation controller in code) using initWithNavigationBarClass:toolbarClass:.
I'm looking at new ways of doing things, and I was wondering how to, in a note app that is built from a Master Detail application template, let the user (in app) tap and change the title of the note in the detail view controller.
http://i.stack.imgur.com/KYO6F.png
So if the user taps "Note", they will be able to change the title of the note altogether.
Is there a way to do this?
As I commented basic idea for this question.
You can add UIView as subview on navigationBar with UIbutton and then on tap you can replace it with UITextField get the new title from user and update.
Or this You can add single UITextField as titleView on UINavigationBar like
self.navigationItem.titleView = youtextField;
Hope this will help you
My app is supposed to run both on iOS 7 and iOS 6 but I am seeing a bit of different behavior with iOS 7. As per my observations iOS7 automatically sets the button to “Back” instead of previous screen’s title when the title is too long. Has anyone faced the same issue. Any clue?
iOS 6 --> Back button title reads "Customer Details" and screen title is "Details"
iOS 7 --> Back button title reads "Back" and screen title is "Details"
Before you segue from your FirstNavigationController to SecondNavigationController. Check if the title of UINavigationItem of FirstNavigationController is not nil,
From Documentation.
When the receiver is on the navigation item stack and is second from
the top—in other words, its view controller manages the views that the
user would navigate back to—the value in this property is used for the
back button on the top-most navigation bar. If the value of this
property is nil, the system uses the string “Back” as the text of the
back button.
No, this does happen because (I assume) because Apple does not want the title pushed right because of long back button text. This has happened many times in my apps. You can set a custom button title if you click on the navigation bar in IB and enter text in the back button field. I would go for a shortening of the previous title, such as 'Details' in your case.