Segue through navigationcontroller - ios

So I have a button in [2] and it pushes to [3] through the Navigation Controller so I can go back to [2] with the "Back" button in the toolbar. This all works fine.
In [4] I have a button too and I want it to go to [3]. But it should also go through the navigation controller so that when I press "Back" I can return to [2] again.
So actually I want the button on [4] to go like [ 1 ][ 2 ][ 3 ] so that I can return to [2] from [3]
#IBAction func showKaart(sender: AnyObject) {
performSegueWithIdentifier("menuToKaart", sender: sender)
}

If I understand your question, I believe try it.
Mind your root view controller is vc[2], ok?
You push from vc[2] > vc[3], next press back and return to vc[2], that's ok!
You push from vc[4] > vc[3], next press back and return to vc[4], but you need back to vc[2]?
For this logic you can create your custom behavior to vc[3]
For your vc[3] I do this to control behavior.
class ViewController3:UIViewController{
var backToRoot:Bool = false;
override func viewDidLoad() {
super.viewDidLoad();
self.hideAndAddNewBackButton();
}
private func hideAndAddNewBackButton(){
self.navigationItem.hidesBackButton = true
let newBackButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: "back:")
self.navigationItem.leftBarButtonItem = newBackButton;
}
func back(sender: UIBarButtonItem) {
if backToRoot{
self.navigationController?.popToRootViewControllerAnimated(true);
}else{
self.navigationController?.popViewControllerAnimated(true)
}
}
func needBackToRoot(){
backToRoot = true;
}
}
Now in vc[4] I think you can modify the back button behavior of your vc[3]
I mind two way to do with your vc[4]
First using performSegue.
class ViewController4PerfomSegue:UIViewController{
#IBAction func pressButtonToPushViewController3(sender:AnyObject?){
self.performSegueWithIdentifier("showViewController3", sender: nil);
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let viewController3 = segue.destinationViewController as? ViewController3{
viewController3.needBackToRoot();
}
}
}
Second with push manual in your navigation view controller
class ViewController4Push:UIViewController{
#IBAction func pressButtonToPushViewController3(sender:AnyObject?){
let viewController3 = ViewController3(nibName: "ViewController3", bundle: nil);
viewController3.needBackToRoot();
self.navigationController?.pushViewController(viewController3, animated: true);
}
}
Edit: new way to instantiate from storyboard
class ViewController4Push:UIViewController{
#IBAction func pressButtonToPushViewController3(sender:AnyObject?){
if let viewController3 = storyboard!.instantiateViewControllerWithIdentifier("ViewController3") as? ViewController3{
viewController3.needBackToRoot();
self.navigationController?.pushViewController(viewController3, animated: true);
}
}
}
Edit: removing when new view was presented
class ViewController4Push:UIViewController, UINavigationControllerDelegate{
#IBAction func pressButtonToPushViewController3(sender:AnyObject?){
if let viewController3 = storyboard!.instantiateViewControllerWithIdentifier("ViewController3") as? ViewController3{
viewController3.needBackToRoot();
self.navigationController?.delegate = self;
self.navigationController?.pushViewController(viewController3, animated: true);
}
}
func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool) {
self.navigationController?.delegate = nil;
self.dismissViewControllerAnimated(false, completion: nil);
//or self.removeFromParentViewController();
}
}
I hope help you, if I understand the problem
Edit: after talk in chat with Sinan we resolve it with simple way, just force back present the root element of application
class ViewCustomController:UIViewController{
override func viewDidLoad() {
super.viewDidLoad();
self.hideAndAddNewBackButton();
}
private func hideAndAddNewBackButton(){
self.navigationItem.hidesBackButton = true
let newBackButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: "back:")
self.navigationItem.leftBarButtonItem = newBackButton;
}
func back(sender: UIBarButtonItem) {
if let viewControllerRoot = storyboard!.instantiateViewControllerWithIdentifier("ViewControllerRoot") as? ViewControllerRoot{
self.navigationController?.pushViewController(viewController2, animated: true);
}
}
}

[4] needs to be embedded in a navigation controller. After that, change you #IBAction to use pushViewController:Animated: on the navigationController instead of performSegueWithIdentifier

Related

Save actions on previous ViewController

I have my main screen with only one button on it "Show next screen". When the second screen(VC) pops up it has 2 buttons (go back and toSelect button).
My goal is to when I show my second screen and select a button on it then go back to first. The button on my second screen will stay selected. How can I do that?
So basically I need to save my actions on the second screen so if I go back to it it will show everything I did.
What is the best way to do it?
Storyboard
The easiest way to achieve this using Delegate and protocol.
you should listen and save the changes of SecondViewController at FirstViewController using delegate methods.
And when you are presenting the secondViewController you will share the saved changes to secondViewController so that button can be selected on behalf of that information
Code -
class FirstViewController: UIViewController {
//secondViewController States
private var isButtonSelected = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func gotoSecondVCAction(_ sender: Any) {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
guard let secondVC = storyBoard.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController else { return }
secondVC.isButtonSelected = isButtonSelected
secondVC.delegate = self
self.present(secondVC, animated: true, completion: nil)
}
}
extension FirstViewController: ButtonSelectionProtocol {
func button(isSelected: Bool) {
isButtonSelected = isSelected
}
}
and for secondViewController
protocol ButtonSelectionProtocol {
func button(isSelected:Bool)
}
class SecondViewController: UIViewController {
var isButtonSelected : Bool = false
var delegate:ButtonSelectionProtocol?
#IBOutlet weak var selectButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
if isButtonSelected {
selectButton.tintColor = .red
selectButton.setTitle("Selected", for: .normal)
}else{
selectButton.tintColor = .green
selectButton.setTitle("Select Me", for: .normal)
}
}
#IBAction func gobackAction(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
#IBAction func selectAction(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
isButtonSelected.toggle()
delegate?.button(isSelected: isButtonSelected)
}
}

Show other array in next view controller depending on button pressed in previous

I spent hours to make this work but I am trying to show an array in a view controller based on the button that is pressed in the previous view. So I want to use the same view controller but with different data.
In the view controller:
#IBAction func firstDeck(_ sender: UIButton) {
var dataSource : CardsDataModel? {
didSet {
label.text = cardsDeck.FirstDate()
}
}
}
#IBAction func secondDeck(_ sender: UIButton) {
var dataSource : CardsDataModel? {
didSet {
label.text = cardsDeck.PizzaFriends()
}
}
}
So there are two cardDecks: PizzaFriends and FirstDates. I tried using IBAction from the buttons to then show the relevant cardsDeck but without success. The cards are empty.
Declare an Array of String type variable in NextViewController
var someData = [String]()
In viewDidLoad() method of NextViewController add this
print("Some Data: \(someData)")
In the PreviousViewController in the IBAction methods present/push the NextViewController with assign someText variable according to which button has been pressed
#IBAction func firstDeck(_ sender: UIButton) {
let vc = NextViewController()
vc.someData = cardsDeck.FirstDate()
// If you want to present NextViewController
present(vc, animated: true, completion: nil)
// If you want to push NextViewController to navigation stack
//navigationController?.pushViewController(vc, animated: true)
}
#IBAction func secondDeck(_ sender: UIButton) {
let vc = NextViewController()
vc.someData = cardsDeck.PizzaFriends()
// If you want to present NextViewController
present(vc, animated: true, completion: nil)
// If you want to push NextViewController to navigation stack
//navigationController?.pushViewController(vc, animated: true)
}
Here is a sample NextViewController
class NextViewController: UIViewController {
var someData = [String]()
var cardView = SwipeCardView(frame: CGRect(x: 10, y: 150, width: 300, height: 600))
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
self.view.addSubview(cardView)
cardView.label.text = "\(someData)"
}
}

UIBarButton click to set flag value using Swift 4.2

My scenario, I am having Two UIBarButton with action method, Here, whenever I am clicking Done and Cancel button I am moving to another ViewController. Once user clicked the Done barbutton I need to set some flag value and validate it another ViewController for button clicked or not clicked.
My ViewController One
let barButtonItem = UIBarButtonItem(image: UIImage(named: "backImgs"),
style: .plain,
target: self,
action: #selector(menuButtonTapped))
self.navigationItem.rightBarButtonItem = barButtonItem
#objc fileprivate func menuButtonTapped() { // here I need to set flag value }
My ViewController Two
class ViewControllertwo: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//Here need to validate flag values to button clicked or not
}
}
I partially understand your question , in here you need to go with tag concept, for e.g
override func viewDidLoad() {
super.viewDidLoad()
let barButtonItem = UIBarButtonItem(image: UIImage(named: "backImgs"),
style: .plain,
target: self,
action: #selector(menuButtonTapped(_:)))
barButtonItem.tag = 20
let cancelButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(menuButtonTapped(_:)))
cancelButton.tag = 10
self.navigationItem.rightBarButtonItem = barButtonItem
self.navigationItem.leftBarButtonItem = cancelButton
}
handle your target function is like
#objc fileprivate func menuButtonTapped(_ sender: UIBarButtonItem) {
// if you dont want the tag concept, use title property for check which button tapped //print("get Tapped button title == \(sender.title)")
//if sender.tag == 20{
// clicked for another VC button, add your segue code here
// }else{
// pressed cancel button
// }
let vcTwo = self.storyboard?.instantiateViewController(withIdentifier: "ViewControllertwo") as! ViewControllertwo
vcTwo.getSelectedTag = sender.tag
self.navigationController?.pushViewController(vcTwo, animated: true)
}
on your VC2 create the one global Int for get the tag where its comes from,
** ViewControllertwo**
class ViewControllertwo : UIViewController {
var getSelectedTag = 0
override func viewDidLoad() {
super.viewDidLoad()
if getSelectedTag == 20 {
//pressed menu Tapped
}
}
}
It's hard to tell from your question, but assuming you are presenting ViewControllerOne from ViewControllerTwo, you're going to want to use the delegate pattern for this. This is similar to the way you use table/collection views, and you are essentially telling ViewControllerTwo to be ViewControllerOne's delegate so that it can react to the buttons being pressed.
Start by creating a protocol that defines the messages that ViewControllerOne can send to its delegate:
protocol ViewControllerOneDelegate: AnyObject {
func viewControllerOneDidTapDone(_ viewController: ViewControllerOne)
func viewControllerOneDidTapCancel(_ viewController: ViewControllerOne)
}
Then extend ViewControllerTwo to implement your protocol:
extension ViewControllerTwo: ViewControllerOneDelegate {
func viewControllerOneDidTapDone(_ viewController: ViewControllerOne) {
// Set your flag or do whatever you need to do on 'Done'.
// Then dismiss viewController.
}
func viewControllerOneDidTapCancel(_ viewController: ViewControllerOne) {
// Dismiss viewController
}
}
In ViewControllerOne, keep the delegate as a weak property and call the delegate methods on button press:
class ViewControllerOne: UIViewController {
weak var delegate: ViewControllerOneDelegate?
#objc private func donePressed() {
delegate?.viewControllerOneDidTapDone(self)
}
#objc private func cancelPressed() {
delegate?.viewControllerOneDidTapCancel(self)
}
}
Lastly, somewhere in ViewControllerTwo, you need to set yourself as ViewControllerOne's delegate. This will likely be when creating ViewControllerOne:
class ViewControllerTwo: UIViewController {
...
private func presentViewControllerOne() {
let viewControllerOne = ViewControllerOne(nibName:nil, bundle: nil)
viewControllerOne.delegate = self
// Present or push viewControllerOne
}
...
}
As I understand your question the solution is -
ViewContorllerOne
class ViewControllerOne : UIViewController {
var isMenubuttonTapped : Bool = false
override func viewDidLoad() {
super.viewDidLoad()
self.actionToPushOnViewControllerTwo()
NotificationCenter.default.addObserver(self, selector: #selector(actioFire), name: NSNotification.Name.init("MenuButtonTapped"), object: nil)
}
//Call from any where in viewControllerOne
func actionToPushOnViewControllerTwo() {
let viewControllerTwo : ViewControllerTwo = self.storyboard?.instantiateViewController(withIdentifier: "ViewControllerTwo") as! ViewControllerTwo
self.present(viewControllerTwo, animated: true, completion: nil)
}
#objc func actioFire(_ notification: Notification) {
print(notification.userInfo!["isMenuButtonTapped"] as Any)
if let isMenuButtonTapped = notification.userInfo!["isMenuButtonTapped"] as? Bool {
self.isMenubuttonTapped = isMenuButtonTapped
}
}
}
ViewControllerTwo
class ViewControllerTwo : UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let barButtonItem = UIBarButtonItem(image: UIImage(named: "backImgs"),
style: .plain,
target: self,
action: #selector(menuButtonTapped))
self.navigationItem.rightBarButtonItem = barButtonItem
}
#objc fileprivate func menuButtonTapped() {
// here I need to set flag value
self.dismiss(animated: true) {
NotificationCenter.default.post(name: Notification.Name("MenuButtonTapped"),
object: nil,
userInfo:["isMenuButtonTapped": true])
}
}
}
Another Easy Solution is
self.dismiss(animated: true) {
if let tabController = self.presentingViewController as? UITabBarController {
if let navController = tabController.selectedViewController as? UINavigationController {
if let secondTab = navController.viewControllers.first as? HomeViewController {
secondTab.tfData = "YES"
}
} else {
if let secondTab = tabController.selectedViewController as? HomeViewController {
secondTab.tfData = "YES"
}
}
}
}

How to go back from one viewcontroller to other viewcontroller

I have a simple one for you guys. I have created a back button on a UITableviewController, and want to set that back button to my other UIViewController(NewTableViewController).
here i implemement back button
let newBackButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.plain, target: self, action: #selector(NewTableViewController.back(sender:)))
self.navigationItem.leftBarButtonItem = newBackButton
and action is
func back(sender: UIBarButtonItem) {
// perform your custom action
//....
// go back to the previuos view controller
_ = navigationController?.navigationController?.self.dismiss(animated: true)
}
but i am unable to go back
Thanks for the help you guys. Please tell me what I am missing.
Try this for swift 3
If you use model view controller
func back(sender: UIBarButtonItem) {
self.dismiss(animated: true, completion: {});
}
OR
If you use push
func back(sender: UIBarButtonItem) {
if let navController = self.navigationController {
navController.popViewController(animated: true)
}
}

Navigation title disappears after use of custom back button

I have 3 pages
Page 1: Menu
Page 2: Menu > Navigation Controller > Map listview
Page 3: Menu > Navigation Controller > Map
It's possible to switch between page 2 and 3 but when you click "Back" it always goes to page 1 and I did this using a custom back button.
After having used the custom back button once the following problem appears:
When I go to page 2 or 3 from the Menu page (Page 1) the navigation title appears and in less than a second it disappears. How is this possible?
These are the functions I am using:
private func hideAndAddNewBackButton(){
if backToRoot{
self.navigationItem.hidesBackButton = true
let newBackButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: "back:")
self.navigationItem.leftBarButtonItem = newBackButton;
self.title = "Locaties"
}
}
func back(sender: UIBarButtonItem) {
if let viewController2 = storyboard!.instantiateViewControllerWithIdentifier("ViewController2") as? ViewController2{
self.navigationController?.pushViewController(viewController2, animated: true);
}
}
func needBackToRoot(){
backToRoot = true;
}
And this is in my viewDidLoad():
var backToRoot:Bool = false;
override func viewDidLoad() {
super.viewDidLoad()
self.hideAndAddNewBackButton();
}
My switch button:
#IBAction func showLijst(sender: AnyObject) {
if let viewController3 = storyboard!.instantiateViewControllerWithIdentifier("Lijst") as? KaartListview{
viewController3.needBackToRoot();
self.navigationController?.pushViewController(viewController3, animated: true);
}
}
In my case problem was creating custom back button and setting in pushed controller
self.navigationController?.navigationBar.topItem?.title = ""
My solutions is :
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.isNavigationBarHidden = false
self.navigationController?.navigationBar.topItem?.title = "SomeTitle"
}
I had a similar issue before and I fixed by using:
navigationController?.navigationBarHidden = false
In the viewDidLoad() function
Like this:
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBarHidden = false
}

Resources