Change title of navigation controller from second view controller? - ios

I have a view controller which has embedded a navigation controller.
From this view controller I am being able to change the title of the navigation bar with navigationItem.title = "title".
Furthermore I have another tableview controller and I want to update the tile of the navigation controller also from here, this tableview controller acts as a Slide Out Menu for the first view controller.
Navigation controller and tableview controller are not connected directly but I use a library called SWRevealViewController to create and connect the slide out menu with first view controller.
I have tried these codes:ViewController().navigationItem.title = "secondTitle"
I have also tried to put the process of changing the title in first controller in function and create an instance like :ViewController().updateNavTitle(), also tried to crete a segues but without any result.

Create a String variable in your first class and access this property in your Slide Out controller and and update it. Now in your first controller's in viewWillAppear method update the title like below.
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if self.updatedTitle != nil {
self.navigationItem.title = self.updatedTitle//Create this String variable.
}
}

Related

Viewcontroller's navigation bar is added below navigation controller's navigation bar inside tab bar controller

I have a Tab Bar Controller that has a navigationcontroller with a view controller attached.
For some unknown reason the navigation bar of the view controller does not look like it always does. Instead the view controller's navigation bar is added below the navigation controller's.
When I look at the view controllers embedded in the first navigation controller before the Tab Bar Controller is shown, it works as expected.
This it what it should look like
And this
Now when I segue to the Tab Bar Controller which has a new navigation controller with a view controller embedded it looks like this:
I don't want an additional navigation bar below the one provided by the navigation controller.
I want the title and the item of the view controller merged with the navigation controller.
So the final result should display a row with the back button, the title and the bar button item(Search Image)
What am I missing?
I've also tried adding the navigation items programmatically but nothing seemed to work.
Project on github
My Code
//
// SideViewController.swift
// Sample
//
// Created by on 08.02.20.
// Copyright © 2020 . All rights reserved.
//
import UIKit
class SideViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
title = "Search"
}
#objc func action(){
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
There is two ways that I found you can resolve this either by presenting tab bar controller modally or hiding navigation bar of a tab bar controller when view loads.
First solution can be achieved like this:
Open Main.storyboard.
Select last segue in this storyboard(one that navigates to Side storyboard).
Make sure that you have Attribute Inspector selected. Now change Kind attribute to Present Modally and Presentation attribute to Full Screen.
And second solution can be achieved like this:
Create new file by selecting File > New > File > Cocoa Touch Class and press Next.
Change Subclass of: to UITabBarController and name your class to whatever make sense to you.
Then inside of viewDidLoad() paste this navigationController?.navigationBar.isHidden = true in order to hide current navigation bar.
Assign your class to TabViewController in the Side storyboard by selecting TabViewController and changing Class attribute to your class name in Identity Inspector. It should autocomplete when you entering your class name. Press Enter to make sure that you confirm the changes.
Remember to make just one of this two solutions. Which one would it be is up to your needs.

UIView container disappears after adding child view controller

I have a tab bar controller that has two tabs. One is a regular UIViewController and the other is a navigation controller. The navigation controller, I am able to push another view controller on it with a custom inputContainerView with no problems. But when I put a navigationViewController (name from mapbox) on the first tab as a child view, the custom inputContainerView no longer shows up. Even after I remove the child view controller from the first tab.
Adding child to tab 1
...
addChild(navigationViewController)
navigationViewController.view.frame = view.bounds
view.addSubview(navigationViewController.view)
navigationViewController.didMove(toParent: self)
}
func navigationViewControllerDidDismiss(_ navigationViewController: NavigationViewController, byCanceling canceled: Bool) {
navigationViewController.willMove(toParent: nil)
navigationViewController.view.removeFromSuperview()
navigationViewController.removeFromParent()
}
tab 2
override var inputAccessoryView: UIView? {
get { return inputContainerView }
}
override var canBecomeFirstResponder: Bool { return true }
The sequence I am trying to achieve is to add a child view controller to the first tab (navigationViewController which is named this from mapbox) click on the second tab and push a ui view controller on with the inputContainerView showing up. It shows up fine before I add the child view on the first tab but disappears after that
this is what the documentation says:
This method creates a parent-child relationship between the current view controller and the object in the childController parameter. This relationship is necessary when embedding the child view controller’s view into the current view controller’s content. If the new child view controller is already the child of a container view controller, it is removed from that container before being added.
Check the Highlighted part.

Navigation bar won't show after pushing a view controller

I'm trying to move from a View Controller to another.
I worte this function to use when the user tap on a button to move to the new view controller:
#objc private func infoButtonTap(){
let navVC = UINavigationController()
navVC.addChild(AboutViewController())
self.navigationController?.pushViewController(AboutViewController(), animated: true)
}
The problem is that the new view controller is presented on the screen but I don't have a navigation bar and a back button to move back.
I do not use Storyboard as I want to learn coding the UI.
I tried few things I found here on Stackoverflow but none worked for me.
How can I set the new view controller to have a navigation bar with back button?
UINavigationController has a variable isNavigationBarHidden
#objc private func infoButtonTap(){
let navVC = UINavigationController()
navVC.addChild(AboutViewController())
self.navigationController?.isNavigationBarHidden = false
self.navigationController?.pushViewController(AboutViewController(), animated: true)
}
You need to push the view Controller. Try this
let aboutVC = AboutVC()
self.navigationController?.pushViewController(aboutVC, animated: true)
You don't need to write any code.
Select the Root Navigation Controller the will control the app. In the Inspector Bar, select Simulated Metrics ( The Third Selection from the Right in the Inspector) and Check the Box " Is Initial View Controller". Then connect the next View controller which will be in essence the Landing page for the app. Once you connect other View Controllers to that View controller via a button for instance ( Select the button, then press Control Key + Drag to View Controller, select Show) , you will see the navigation Bar with "Back" displayed. Once that's done, you can add other view controllers and connect them from the landing page view controller and the Navigation Bars will be displayed.
For navigation to be visible and of use in an app , first you need to set up a Navigation controller with a Root view controller i.e your first controller and from there you can use push method on your navigation controller object to push a controller on to the stack.
For eg
let navVC = UINavigationController.init(rootViewController: YourFirstViewControllerObject())
navVC.pushViewController(NewViewControllerObj(), animated: true)

Swift: How to segue between view controllers and use navigation bar to go backwards within a child view controller (XLPagerTabStrip)

I am currently implementing the XLPagerTabStrip (https://github.com/xmartlabs/XLPagerTabStrip) which effectively creates a tab bar at the top of the view controller. I want to be able to segue to a new view controller from one of the tabbed controllers and be able to use the navigation bar to move backwards (or a custom version of the navigation bar if this isn't possible).
XLPagerTabStrip provides the moveToViewController and moveToViewControllerAtIndex functions to navigate between child view controllers, but this method doesn't allow use of a navigation bar to go backwards.
Conceptually XLPagerTabStrip is a collection of view controllers declared and initialized during the XLPagerTabStrip model creation.
It has virtually no sense to use a UINavigationController if you already have all the viewcontrollers available.
You can create a global var previousIndex to store the previous viewController index and allow users to go back by using canonical methods:
func moveToViewControllerAtIndex(index: Int)
func moveToViewControllerAtIndex(index: Int, animated: Bool)
func moveToViewController(viewController: UIViewController)
func moveToViewController(viewController: UIViewController, animated: Bool)
About a new viewController, suppose you have 4 viewControllers that built your container (XLPagerTabStrip) named for example z1, z2, z3 e z4.
You can embed to z4 a UINavigationController (so it have the z4 controller as rootViewController) and start to push or pop your external views. When you want to return to your z4 you can do popToRootViewControllerAnimated to your UINavigationController
When you are go back to z4 , here you can handle your global var previousIndex to moving inside XLPagerTabStrip.
I'm not familiar with XLPagerTabStrip, but I had a similar problem recently and the solution was to use an unwind segue to go back to the previous view controller. It's pretty trivial to implement so probably worth a try.
To navigate back to your previous view tab controller, you had initially navigated from;
Embed your new view controller, from which you wish to navigate
away from in a navigation bar
Connect it's Navigation Bar Button to the Parent view containing the
tab bar by dragging a segue between the 2 views
Create a global variable in App delegate to store current index
which you will use in the Parent view to determine what tab view
controller to be shown
var previousIndex: Int = 0 //0 being a random tab index I have chosen
In your new view controller's (the one you wish to segue from)
viewdidload function, create an instance of your global variable as
shown below and assign a value to represent a representative index
of the child tab bar view controller which houses it.
//Global variable instance to set tab index on segue
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.previousIndex = 2
You can write this for as many child-tab connected views as you wish, remembering to set the appropriate child-tab index you wish to segue back to
Now, create a class property to reference your global variable and a function in your Parent view as shown below
let appDelegatefetch = UIApplication.shared.delegate as! AppDelegate
The function
func moveToViewControllerAtIndex(){
if (appDelegatefetch.previousIndex == 1){
self.moveToViewControllerAtIndex((self.appDelegatefetch.previousIndex), animated: false)
} else if (appDelegatefetch.previousIndex == 2){
self.moveToViewControllerAtIndex((self.appDelegatefetch.previousIndex), animated: false)
}
}
You may now call this function in the Parent View Controller's viewDidLoad, as shown below.
moveToViewControllerAtIndex()
Run your project and that's it.

Reusing UIViewController for two Tab bar items

I have 1 tab bar controller in storyboard and 1 UIViewController associated with it. I would like to re-use the same UIViewController in order to create second item in tab bar. When I am creating second relation from tab bar to view controller I need to specify 2 different items names. How can I re-use same view controller and set different items names from storyboard? If not possible to do it in storyboard, then do I have to rename each in tab bar controller class or there is better way?
I was going to provide different data to view controller in prepareforsegue.
UPDATE:
little more details and clarification
In above screenshot marked VC at the moment is reachable a) directly from tab, b) through 3 transitions. I want to add another DIRECT relation to initial tab bar, just like in case of "a".
I can give you a little tweak for that and at least that worked for me.
Drag a tabbarcontroller and associated tab item view controllers to
your storyboard. Name them as you like.
Create an extra view controller that you want to reuse from your storyboard.
Add container views to each tab item view controllers and remove their default embedded view controllers.
Create embed segue from each tab item controller to your re-usuable view controller.
The configuration looks something like the following:
Thus you can use the same embedded VC for different tabbar item. Obviously if you need the reference of the tabbarcontroller, you need to use self.parentViewController.tabBarController instead of self.tabBarController directly. But it solves the issue of reusing a VC right from the storyboard.
I've found much simpler solution using storyboard only.
Setup your storyboard like this:
Then in your Navigation Controller Identity Inspector set Restoration ID like this:
And in your ViewController class file put the following code:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationItem.title = parent?.restorationIdentifier
label.text = parent?.restorationIdentifier
}
or do what you like based on parent?.restorationIdentifier value
If you don't want the Navigation TopBar to appear on the ViewController just set it to None in Attributes Inspector of the desired Navigation Controller like this:
That's it! Hope it helps.
Yes you can.
All you need to do is to create a new View Controller in StoryBoard as if there is going to be a different View Controller for tab 2. Then Select the 2nd view controller and simply add its class name the same classname of view controller 1
Things to note:
When you are sharing the same view controller class (.m ad .h) files, each tab will create a NEW instance of that class.
Edit:
This works as long as you have either a "custom" cell scenario (i.e. reusing two table view controllers) OR, have all your views inside a "container view" (i.e. reusing UIView).
I needed slightly different solution than the accepted answer. I needed to use same Table View Controller with the different data source for different tab bar items. So in the storyboard, i created two Navigation Controllers with same classes like this;
I also give different "Restoration ID" to each of them.
For the first one, I gave "navCont1" and "navCont2" for the second one.
In subclass("GeneralNavCont") of these Navigation Controllers; I override init method and check restoration id of self. Then i initiate my TableViewController and set its data source based on ids like this;
class GeneralNavCont: UINavigationController {
var dataSource1 = [Countries]()
var dataSource2 = [Cities]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initiateTableVCBasedOnId()
}
func initiateTableVCBasedOnId() {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let tableVC = storyBoard.instantiateViewController(withIdentifier: "tableVC") as! MyTableViewController
if self.restorationIdentifier == "navCont1" {
tableVC.dataSource = self.dataSource1
self.viewControllers = [tableVC]
}
else if self.restorationIdentifier == "navCont2" {
tableVC.dataSource = self.dataSource2
self.viewControllers = [tableVC]
}
}
}
Hope it helps someone. Cheers.

Resources