short: I don´t understand how to programmatically add the default back button.
long: I have been asked to write an iOS app, without any previous experience I decided
to follow the advices and code given by Nicola Zaghini.
In the code given along with the article, I really don´t understand
where does the back button come from.
The app has three screens
one to choose a city (folder WeatherLocation)
one that displays all
cities that have been already choosen (folder WeatherList)
one that
displays the weather for a city clicked in the list (folder
WeatherDetail)
There is + button for WeatherLocation:
This button is added in the code but I can not find where
and how is coded the back button in WeatherDetails (see above), and how is coded the action to do when one click the back button.
I search the web and found how to set a button in the NavigationBar:
let leftBarButtonItem: UIBarButtonItem = {
let barButtonItem = UIBarButtonItem(title: "Left Item", style: .plain, target: self, action: nil)
barButtonItem.tintColor = UIColor.red
return barButtonItem
}()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationItem.leftBarButtonItem = leftBarButtonItem
}
I also found that there is a backBarButtonItem
but I could not find how to properly use this property.
Moreover in the code of Nicola Zaghini there is nothing like backBarButtonItem to enable the
back button, neither in the xib and storyboard.
Can someone give me some hints about on how to set the back button ?
Thanks a lot!!
In the code of Nicola Zaghini the secret to have a default back button resides (for example) in the function navigateToWeatherDetail in the class WeatherListDefaultRouter where the new ViewController is pushed on a NavigationController:
func navigateToWeatherDetail(withLocation location: Location) {
if let weatherDetailVC = self.weatherDetailBuilder()?.buildWeatherDetailModule(withLocation: location) {
self.viewController?.navigationController?.pushViewController(weatherDetailVC, animated: true)
}
}
Related
I have an existing navigation controller delegate that places a menu button on each view controller in the app.
class MyNavigationControllerDelegate: NSObject, UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
let navItem = viewController.navigationItem
let menuBtn = MyCustomMenuButton()
...
navItem.setRightBarButton(menuBtn, animated: false)
}
This works great...I get a menu button in the nav bar for each view. But for some views, I'd like to add another button on the right next to the menu button, so I added this:
class CustomViewController: UIViewController, UINavigationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let newButton = UIBarButtonItem(title: "(+)", style: .plain, target: nil, action: nil)
self.navigationItem.rightBarButtonItem = newButton
}
}
But this has no effect. The menu button is still there but the new button is not added. How should this be done then?
But this has no effect
Yes, it does. But you don't have time to see the effect. You are saying the same thing twice, because setRightBarButtonItem is the same as rightBarButtonItem =... So whichever one you say second, that is the one that is ultimately obeyed; either way, it rips the existing right bar button item out and replaces it with the other one.
If the goal is to have multiple right bar button items, that is what the rightBarButtonItems is for (notice the plural). You can call setRightBarButtonItems instead (again, notice the plural). Looking to see whether there is already a right bar button item and taking that into account is up to you, of course. There is no magical append method.
I'm trying to build a GoogleMaps based application. When the user is on MapViewController, I want them to be able to choose a location on the map and click Next at the Top right. Doing so should take them to another screen with a description of the location (HomeViewController). I'm stuck on implementing the Next button. My current code for the button looks like this...
override func viewDidLoad()
{
....
navigationItem.rightBarButtonItem = UIBarButtonItem(title:"Next", style: .plain, target: self, action: #selector(MapViewController.next as (MapViewController) -> () -> ()))
}
func next()
{
print("next")
if let navController = self.navigationController, let viewController = self.storyboard?.instantiateViewController(withIdentifier: "indentfier") as? HomeViewController{
navController.pushViewController(viewController, animated: true)
}
}
I ran it at first with just the print("next") and it worked (i.e., it just printed "next" to the console). When I added the second line with the push, the app started to crash when I clicked Next. I also got a SIGABRT error on my app delegate.
Note: HomeViewController is actually the home page; it's a previous screen that the user will have already seen a 4-5 screens before the map. I basically want them to go back a few screens to the home page when they hit Next.
Any help would be appreciated. Thank you.
Replace
navigationItem.rightBarButtonItem = UIBarButtonItem(title:"Next", style: .plain, target: self, action: #selector(self.next(_:)))
#objc func next(_ bar:UIBarButtonItem) {
}
Edit: I forgot to mention that I can't use Apple's predefined edit button because I need the button in the toolbar not the navigation bar (I couldn't figure out a way to add Apple's edit button on the toolbar. If this is possible then please let me know).
I know this question seems like a lot of other questions that have been asked but I have tried the solutions from all of those questions and non of them have helped me solve this problem.
I've researched this problem and tried every solution that I found and could think of.
I've got a UIBarButtonItem which is in my toolbar. It is working as an edit button, so when clicked I want the title to change back to Done. However, whenever I change the title nothing happens. I've tested this value as well and when I print out the value for title I get nil every time. I can't figure this out...
#IBOutlet weak var customEditButton: UIBarButtonItem!
func viewDidLoad() {
super.viewDidLoad()
tableView.setEditing(false, animated: false)
customEditButton.title? = "Edit"
print("customEditButton = \(customEditButton.title)") //This prints nil
...
}
#IBAction func editButtonIsClicked(_ sender: UIBarButtonItem) {
print("MarksTable: editButtonIsClicked")
if (self.tableView.isEditing) {
tableView.setEditing(false, animated: true)
customEditButton.title? = "Edit"
}
else {
tableView.setEditing(true, animated: true)
customEditButton.title? = "Done"
}
}
This not the only thing I've tried. I have also tried
customEditButton = UIBarButtonItem.init(title: "Done", ...)
but this also failed.
Does anyone know why this is happening or have a solution to the problem?
So I was able to reproduce your issue on my own project and I have it running correctly.
It is possible that your issue lies in the System Item type of the button you have added to the Toolbar. Go to storyboards, select your button, and make sure you set its System Item to Custom in the Attributes Inspector, instead of Edit. Initially, I tried using Edit but its just not as simple to change the title as if you have it set as Custom.
After this I created an outlet and an action from the button, just as you did in your code.
Here's the outlet ->
#IBOutlet weak var editBarButton: UIBarButtonItem!
And here's the button action:
#IBAction func tappedEditButton(sender: UIBarButtonItem) {
if tableView.editing {
tableView.setEditing(false, animated: true)
editBarButton.title = "Edit"
} else {
tableView.setEditing(true, animated: true)
editBarButton.title = "Done"
}
Hopefully this works well to solve your problem, best of luck!
I am unable to add a tool bar to my tableView using the Xcode main.storyboard.
Thus, I tried coding it in manually in the viewDidLoad()
let logOutButton = UIBarButtonItem(title: "Log Out", style: UIBarButtonItemStyle.Bordered, target: self, action: "logOut")
var bottomBarButtonArray = [UIBarButtonItem]()
bottomBarButtonArray.append(logOutButton)
self.navigationController!.setToolbarHidden(false, animated: true)
self.navigationController!.toolbar.items = bottomBarButtonArray
May I know how do I set the logOutButton text and also how to detect if logOutButton has been pressed.
I tried logOutButton.description = "Log Out" but it does not work.
My toolbar does appear but I have no idea how to add the text for the logout button.
The solution is to use UIViewController as parent class and not UITableViewController
How to add a toolbar to a TableView in iOS
If the TableView happens to be embedded in a Navigation Controller, there is an easy solution: you can add the Toolbar straight away in the NavigationController. The checkbox 'Shows Toolbar' in the Attributes Inspector is all you need.
Details: https://stackoverflow.com/a/34832688/5897915
I have this below code that changes the back button image on next screen.
I have 30 screens in my app and i want back button to be same across all 30 screens. Is it possible that I don't copy paste this code on all 30 screens and just write it once and rather reuse it across 30 screens.
Also, the code attached with back button should work fine on all screens when i reuse it
I am using iOS 8 and Xcode 6.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let backButtonImage: UIImage = UIImage(named: "back")!
var backBarItem: UIBarButtonItem = UIBarButtonItem(image: backButtonImage, style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method"))
segue.destinationViewController.navigationItem.leftBarButtonItem = backBarItem;
}
func method() {
self.navigationController?.popViewControllerAnimated(true)
}
You can change it globally
UINavigationBar.appearance().backIndicatorImage = UIImage(named: "custom-back")
UINavigationBar.appearance().backIndicatorTransitionMaskImage = UIImage(named: "custom-back")
Or per navigation controller.
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.backIndicatorImage = UIImage(named: "custom-back")
navigationController?.navigationBar.backIndicatorTransitionMaskImage = UIImage(named: "custom-back")
}
Full detail here https://sarunw.com/posts/how-to-change-back-button-image/
To general change the appearance of UI-Elements in iOS look at UIAppearance. This way you can set it once and it will be everywhere in your app.
I would recommend setting it in the AppDelegate application:didFinishLaunchingWithOptions:.
Try this:
let backImg: UIImage = UIImage(named: "back")!
UIBarButtonItem.appearance().setBackButtonBackgroundImage(backImg, forState: .Normal, barMetrics: .Default)
I only have one navigation Controller in my app, so this may or may not be helpful. But, I created a subclass of UINavigationController. Then in this subclass, I override the pushViewController method:
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
let pushingVC = viewControllers[viewControllers.count - 1]
let backItem = UIBarButtonItem()
backItem.title = ""
pushingVC.navigationItem.backBarButtonItem = backItem
super.pushViewController(viewController, animated: animated)
}
This, makes it so every time a viewController is pushed, from my customNavigationController, it uses the custom back button for every view. You have to make sure you change your UINavigationControllers type to your custom Subclass. But, this works for me in Swift 3.0.
You could use appearance()
Swift
let backImage = UIImage(named: "back")
UINavigationBar.appearance().backIndicatorImage = backImage
UINavigationBar.appearance().backIndicatorTransitionMaskImage = backImage
UIBarButtonItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor:
UIColor.white], for: .normal)
UIBarButtonItem.appearance().tintColor = UIColor.green
I'm not quite sure what you wanted, so I'll answer most of what I think you could want for your sake and anyone looking at this in the future.
First: You want a back button similar to those on default apple apps. To do so, you need to a) get a reference to the destination scene and it's view controller. I will assume you have done so and set it equal to controller for future reference. b) You need to set the left bar button item. Set it with:
controller.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Insert Title Here!!", style: UIBarButtonItemStyle.Plain, target: nil, action: nil)
Place all of this in prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) (you will also find the destination scene with this, likely with segue.destinationViewController
Second: You want to use an image named "Back" for all items. If so, repeat step a) above, and insert this handy bit of code:
UIBarButtonItem(image: "Back", style: UIBarButtonItemStyle.Plain, target: nil, action: nil)
I also know you want to not have to copy it, but it's not as if this is that computer intensive anyways and it's probably simplest.
Third: You're smart and don't hate advances in programming so you want to use a storyboard. If so, simply drag in a Navigation Bar from the object menu, add a navigation item, and copy it to all of your scenes. If your scenes are linked to custom classes, then super happy fun time good news, you can simply link the navigation item to your custom class through an IBAction and use that function to do all the fancy coding your heart could ever desire.
Fourth: You really, really don't want to copy anything even if it's not that hard. If so, you can subclass a UIViewController with your own custom class, add the code I mentioned above, and then subclass all your future UIView classes as this. To be honest, I'm not entirely sure this would work and it seems unnecessarily laborious, but it's up to you.
I'm a bit tired right now so sorry for all the things I'm finding funny, but I hope I helped, and please tell me if I missed your point entirely and I can try and think of a solution.