I have a custom "Replace" segue that replaces the current viewcontroller with another. This works good. However the back button title always becomes "Back". The segue works like this:
ViewController A -> ViewController B
ViewController B then performs a replace segue to ViewController C. The stack is then:
ViewController A -> ViewController C
This is the code for ReplaceSegue.swift:
public class ReplaceSegue: UIStoryboardSegue
{
public var animated = true
public override func perform()
{
let navigationController: UINavigationController = sourceViewController.navigationController!
var controllerStack = navigationController.viewControllers
let index = controllerStack.indexOf(sourceViewController)
controllerStack[index!] = destinationViewController
navigationController.setViewControllers(controllerStack, animated: animated)
}
}
And for my ViewController:
func replaceAgendaViewController()
{
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let agendaViewController = mainStoryboard.instantiateViewControllerWithIdentifier("AgendaViewController") as! AgendaViewController
let segue = ReplaceSegue(identifier: replaceSegueId, source: self, destination: agendaViewController) { () -> Void in
}
segue.animated = false
segue.perform()
}
Have tried this code but I understand why it does not work as it sets the navigationItem on the ViewController that is replaced:
navigationItem.backBarButtonItem = UIBarButtonItem(title: " ", style: UIBarButtonItemStyle.Plain, target: nil, action: nil)
I also do not want to set the back button title previous to performing the segue as the ViewController contains other segues that may not want that back button title. Any suggestions?
It was quite easy to fix, I just added the code to the prepareForSegue:sender: in ViewController A:
public override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
switch (segue.identifier!) {
case agendaSegueId:
navigationItem.backBarButtonItem = UIBarButtonItem(title: " ", style: UIBarButtonItemStyle.Plain, target: nil, action: nil)
...
}
}
Related
I am using XLPagerTabStrip library and using the ButtonBarPagerTabStripViewController. This is what the hierarchy looks like:
The ButtonBarPagerTabStripViewController is embedded inside a navigationController and I have two different viewControllers that the ButtonBarPagerTabStripViewController contains. The problem is that I want to change how the navigationBar looks based one either ViewController1 or ViewController2.
For example, when the tab is one viewController1, I want to have a barButton "+". For viewController2, I want to have a barButton of report. However, I cannot make modifications to the navigationController bar from viewController1 and viewController2.
Is there a way?
ButtonBarPagerTabStripViewController class has a override function to handle this.
override func updateIndicator(for viewController: PagerTabStripViewController, fromIndex: Int, toIndex: Int, withProgressPercentage progressPercentage: CGFloat, indexWasChanged: Bool) {
if progressPercentage == 1 {
// Add `+` button to navigation item
} else {
// Add `report` button to navigation item
}
}
Add condition as per your total number of view controllers on the screen.
Update
Please see the below code used in the demo project.
import UIKit
import XLPagerTabStrip
class MainTabBarViewController: ButtonBarPagerTabStripViewController {
var isFirstView: Bool = true
override func viewDidLoad() {
super.viewDidLoad()
}
func getSegmentList() -> [UIViewController] {
let firstViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "FirstViewController")
firstViewController.title = "First"
let secondViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "SecondViewController")
secondViewController.title = "Second"
return [firstViewController, secondViewController]
}
func setUI() {
let addImage = UIImage(systemName: "plus")
let addBarButton = UIBarButtonItem(image: addImage, style: .plain, target: self, action: #selector(addButtonAction(_:)))
let reportImage = UIImage(systemName: "book")
let reportBarButton = UIBarButtonItem(image: reportImage, style: .plain, target: self, action: #selector(reportButtonAction(_:)))
navigationItem.rightBarButtonItem = isFirstView ? addBarButton : reportBarButton
}
#IBAction func addButtonAction(_ sender: UIBarButtonItem) {
print("Add button action")
// Add button action
}
#IBAction func reportButtonAction(_ sender: UIBarButtonItem) {
print("Report button action")
// Report button action
}
override func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
return getSegmentList()
}
override func updateIndicator(for viewController: PagerTabStripViewController, fromIndex: Int, toIndex: Int, withProgressPercentage progressPercentage: CGFloat, indexWasChanged: Bool) {
if progressPercentage == 1 {
let viewController = viewController.viewControllers[toIndex] as? FirstViewController
isFirstView = viewController?.title == "First"
setUI()
}
}
}
Output:
I have a Navigation Bar with two buttons: Back and Add. I need to transfer data (UIImage) to second View Controller (ViewControllerFilters2), when I click on the add button. I have the "prepare for segue" function but it doesn't work. When I click on "Add", I go to the second controller, but imageView doesn't have an image.
I also have another button "Apply" on view controller, and for this button this function works but not for button on navigation bar.
I tried to change my code, but I don't have a lot of knowledge to do it. And don't know, where is the problem.
I want my Add button do the same function as Apply button, i.e. I want delete Apply button and change it to Add button
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "✔", style: .plain, target: self, action: #selector(addTapped))
}
#objc func addTapped() {
let filterTwoController = self.storyboard?.instantiateViewController(withIdentifier: "filter2") as! ViewControllerFilters2
self.navigationController?.pushViewController(filterTwoController, animated: true)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let nextController = segue.destination as? ViewControllerFilters2
nextController?.filteredImage = imageView.image!
}
#objc func addTapped() {
let filterTwoController = self.storyboard?.instantiateViewController(withIdentifier: "filter2") as! ViewControllerFilters2
filterTwoController.filteredImage = imageView.image!
self.navigationController?.pushViewController(filterTwoController, animated: true)
}
that should fix your issue, because the navigationController?.pushViewController has nothing to do with the segue
In order to resolve the issue, you should do the following:
Make sure that there is a segue created (from the navigation item to the next view controller) on your storyboard. If you don't know how to do it, check this. You could add the bar button from the storyboard thus create the segue.
Currently, you are calling navigationController?.pushViewController, which is not related to the segue, what you should do instead is to call:
self.performSegueWithIdentifier ("SecondViewController", sender: self)
Change this:
#objc func addTapped() {
let filterTwoController = self.storyboard?.instantiateViewController(withIdentifier: "filter2") as! ViewControllerFilters2
self.navigationController?.pushViewController(filterTwoController, animated: true)
}
to this:
#objc func addTapped() {
let filterTwoController = self.storyboard?.instantiateViewController(withIdentifier: "filter2") as! ViewControllerFilters2
filterTwoController.filteredImage = imageView.image!
self.navigationController?.pushViewController(filterTwoController, animated: true)
}
As Ahmad F said, you are calling navigationController?.pushViewController, which is not related to the segue, so you need to set the image before you push the view controller.
let backButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.plain, target: self, action: Selector(("HomeTabController")))
self.navigationItem.leftBarButtonItem = backButton
The above code is the creation of button in navigationController but I can create a button cannot write a specific view controller to open.
I have tried with popViewController and popToRootViewController action, need a specific code for opening a particular viewController in swift, with the help of the particular viewController storyboard id and viewcontrollername.
You need to add func name in #selctor() (Swift 4 version)
let backButton = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(goToViewController(_:)))
self.navigationItem.leftBarButtonItem = backButton
You need to create a func.
#objc func goToViewController(_ sender: UIBarButtonItem) {
//write code here to open a view controller
let storyboard = "Main"
let viewControllerIdentifier = "HomeVC"
let viewController = UIStoryboard(name: storyboard, bundle: nil).instantiateViewController(withIdentifier: viewControllerIdentifier) as! HomeVC
//push/present "viewController"
}
in this code just replace ChatVC name to your viewcontroller name
#objc func goToViewController(_ sender: UIBarButtonItem) {
for controller in self.navigationController!.viewControllers as Array {
if controller.isKind(of: ChatVC.self) {
self.navigationController!.popToViewController(controller, animated: true)
break
} else {
self.navigationController?.popViewController(animated: true)
}
}
}
Hi I have two View Controller. there is two segue from first vc to the second vc.I have implemented (with code) right bar button and back button and title in second vc in the view did load .when I segue with button I can see them but when I segue by view controller(for choosing table view cell (did select)) I don't see them
how should I fix them???
this is in the second view did load
override func viewDidLoad() {
super.viewDidLoad()
let img = UIImage(named: "delBtn")
if let top = self.navigationController?.navigationBar.topItem {
top.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
}
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: img, style: .plain, target: self, action: #selector(dele))
self.navigationItem.title = "Add/Edit"
pickerS.delegate = self
pickerS.dataSource = self
getMajor()
if preStudent != nil {
receivedData()
}
}
this is segue of first view controller
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let con = controller.fetchedObjects, con.count > 0 {
let obj = con[indexPath.row]
performSegue(withIdentifier: "edit", sender: obj)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "edit" {
if let des = segue.destination as? EditVC {
if let obj = sender as? Student {
des.preStudent = obj
}
}
}
}
Navigation bar is inherited from parent view controller. If your parent view controller is embedded in a navigation controller and you push to a child view controller, your child view controller will have the navigation bar automatically, and thus have the navigation bar items. In your storyboard, check to make sure your segue type is set to show & push. If it's set to present modally, you will lose your navigation bar in your child controller.
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 :)
}