Back button suddenly stopped appearing in navigation bar - ios

I built a simple 'About' page for my app that is simply a webView with local HTML. My Settings are contained within a separate storyboard and the AboutViewController is a view within that storyboard.
When the AboutViewController is presented it no longer shows a back button to go back to the settings.
This has worked perfectly fine for the past two weeks and has suddenly stopped working today. Is there a better way to push the view onto the navigation controller?
let storyboard = UIStoryboard(name: "Settings", bundle: nil)
let aboutViewController = storyboard.instantiateViewControllerWithIdentifier("AboutViewController") as! AboutViewController
self.navigationController?.pushViewController(aboutViewController, animated: true)
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
I have a slightly older version of my app running on my phone and it looks like this:
And now it looks like this:

Well a workaround is to put it back yourself.
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "< Back", style: UIBarButtonItemStyle.Plain, target: self, action: "back")
}
func back()
{
navigationController?.popViewControllerAnimated(true)
}

Related

Change Right Bar Button Items on Current Screen

I have spent all day trying to figure this out and I'm beyond frustrated.
I have a navigation stack and on each screen, based on the content of the screen, I need to hide/show some of the right bar button items. But no matter what I do, the items are changing on the previous screen on the stack, not on the current screen.
My view controllers are all pushed onto a navigation controller. And each view controller can instantiate another view controller and push onto the navigation stack.
let vc = UnifiedArticleViewController()
navigationController?.pushViewController(vc, animated: true)
I have tried the following:
navigationController?.navigationBar.topItem?.rightBarButtonItems = [arrayOfBarButtonItems]
and:
navigationItem.rightBarButtonItems = [arrayOfBarButtonItems]
as well as a variety of other suggestions I've gotten from various stack overflow suggestions.
I have been able to change the title of screens using:
navigationController?.navigationBar.topItem?.title = "New Title Here"
and that works perfectly. What am I doing wrong?
Set the leftBarButtonItems or rightBarButtonItems from the controller you're wanting to set the button(s) on that is in the navigation controller's view stack.
class ViewController: UIViewController {
override func viewDidLoad() {
let leftButton = UIBarButtonItem(title: "Left", style: .done, target: self, action: #selector(leftButtonPressed(_:)))
self.navigationItem.leftBarButtonItems = [leftButton]
let rightButton = UIBarButtonItem(title: "Right", style: .done, target: self, action: #selector(rightButtonPressed(_:)))
self.navigationItem.rightBarButtonItems = [rightButton]
}
#objc func leftButtonPressed(_ sender: UIBarButtonItem) {
}
#objc func rightButtonPressed(_ sender: UIBarButtonItem) {
}
}

Back button shows then quickly disappears

Issue: Upon displaying the second view, the Back button shows and then quickly disappears.
I'd like the Back button to persist on the second view.
Setup:
2 views.
The button that opens the second view is done via a "Show" segue.
SecondVC:
override func viewDidAppear(_ animated: Bool) {
let controller = TipJarViewController<TipJarOptions>()
self.present(controller, animated: false, completion: nil)
}
It seems to happen because of how I'm doing the viewDidAppear. It seems that I'm replacing the entire view with the self.present. I'm not sure what to search for or modify so it can still show the Back button.
Bonus question: Wondering if I'm placing this code in the wrong section. On the transition to the second view the screen is blank for a bit and then will show the view's contents. This doesn't seem like an optimal user experience. Open to any suggestions here.
After moving present to first VC via Frankenstein's suggestion
You don't need to segue into the second controller and then present. Instead, present directly instead of show the controller keeping it as rootViewController of a UINavigationController. Do this on the action:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let controller = UINavigationController(rootViewController:
TipJarViewController<TipJarOptions>())
present(controller, animated: false, completion: nil)
}
Edit: To add back button in TipJarViewController, here is the code:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(handleBack))
}
#objc func handleBack() {
dismiss(animated: true)
}

Hiding the Back Button on a TabbedBarController in Swift

I've a NavigationViewController which segues to a TabbedBarController. I don't want to show the back button on the TabbedBarController.
I've tried both these code snippets in Swift , neither works,
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.navigationItem.hidesBackButton = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationItem.hidesBackButton = true
}
Here's a snap shot,
Here's the tabbed bar view controller,
How can I hide the back button on the Tabbed bar view controller. How can I hide the back button on my tabbed bar controller?
There are quite many ways to do what you want, but what I'm 99.9% sure that would work is that you can add a barButton in your leftBarButtonItems to replace the default backButton of your navigationController:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationItem.leftBarButtonItems = [UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)]
}
Also, when overriding any lifecycle methods of a controller, you might not want to miss anything from the parent class, so don't forget to call its super equivalent like super.viewWillAppear(animated)
I hope this helps!
EDIT: Two ways to do what you want in tabBarController and since I can already picture the flow of your project.
Put the code inside the viewWillAppear of your tabBarController. This means that you might need to subclass the UITabBarController. So it should be like this:
class MyTabBarController: UITabBarController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationItem.leftBarButtonItems = [UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)]
}
}
You should present modally your tabBarController (this is more ideal).

Add a "Done" button to dismiss a programmatically created UIViewController

I'm a swift newbie and made a demo app which has a UIViewController and UITableViewController in the Storyboard. The UIViewController has a Collection View and an embedded navigation controller. On tapping a collection view cell, the app segues to the UITableViewController. I can come back to my UIViewController from the UITableViewController as well. All this works well. Now, some of the rows in my UITableViewController have URLs. On tapping a URL, I programmatically create a webview inside a UIviewcontroller and get the URL to load in it. The issue is that I can't dismiss the webview and get back to my UITableViewController after this. This is the code I have in my UITableViewController class :
// When user taps a row, get the URL and load it in a webview
let mywebViewController = UIViewController()
let webView = UIWebView(frame: mywebViewController.view.bounds)
webView.loadRequest(NSURLRequest(URL: url)) // url from the row a user taps
mywebViewController.view = webView
self.navigationController!.presentViewController(mywebViewController, animated: true, completion: nil)
How can I add a Done button to this programmatically created UIviewcontroller to dismiss the webview and get back to my UITableViewController
You can wrap the mywebViewController in a UINavigationController then set the rightBarButtonItem to UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: "dismiss") like this:
let navController = UINavigationController(rootViewController: mywebViewController)
mywebViewController.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: "dismiss")
self.navigationController!.presentViewController(navController, animated: true, completion: nil)
and add a dismiss function in your UITableViewController:
func dismiss() {
self.dismissViewControllerAnimated(true, completion: nil)
}
Add done button to your presented ViewController and make an action for it.
To dismiss ViewController try this :
self.dismissViewControllerAnimated(true, completion: nil)
You can do one thing.
As you are pushing your mywebViewController into the navigation controller, make the navigation bar visible.
By simply tapping on Back button in the navigation bar you can easily dismiss your mywebViewController.
Hope this helps you. :)
Add button in mywebViewController and in its #IBAction, call
self.dismissViewControllerAnimated(true, completion: nil)
Update for Swift 4 & 5
In the VC you're navigating from
navController.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.dismiss))
Have to declare your selector as an #objc func
#objc func dismiss(){
self.dismiss(animated: true)
}

Can't get a back button on my view controller in Swift

Here's what's going on:
I have a Navigation Controller with A-TableViewController set as root view controller. Once I click on a cell in A, it'll take me to B-ViewController. The navigation controller has an identifier "MessagesViewController". Here's my code thus far in A-TableViewController:
func tableView (tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let sb = UIStoryboard(name: "Main", bundle: nil)
let messagesVC = sb.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController
//Some code here
//This has a back button, but nothing else
self.navigationController?.pushViewController(messagesVC, animated: true)
//This has no back button, but everything else that I intended works
self.navigationController?.presentViewController(messagesVC, animated: true, completion: nil)
I want to be able to go back to A-TableViewController with everything working. Is it the way I'm pushing/presenting the view controller that's messing it up? Anyone have any clue why I've been stuck on this for the past 3 days?
You get built in back button when you push a view on to a navigation view. The presentViewController is modally displaying your view. What I've done in the past is add my own back button to the view and present it. Then when you press it you call dismissViewController.
After Presenting your B-ViewController Try this in viewDidLoad:
let btnBack = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(dismissVC))
btnBack.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.black], for: .normal)
navigationItem.setLeftBarButton(btnBack, animated: true)
#objc func dismissVC() {
self.dismiss(animated: true, completion: nil)
}
You can use the prepareForSegue method to pass data, something like this:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if segue.identifier == "messageSegue" {
let vc: B-ViewController = segue.destinationViewController as! B-ViewController
//then set properties of your new viewController like this
vc.property = dataToPass
}
}
If you are indeed using a navigation controller, than your problem should be quite simple.
Create an #IBAction, and in it, call popToRootViewControllerAnimated, like so:
#IBAction func rootButton(sender: UIButton) {
navigationController?.popToRootViewControllerAnimated(true) // or false :)
}

Resources