Showing a view controller across the app - ios

I am having one view controller which should be hide and show from everywhere in the app without initializing it again. So I just want to know that how can I achieve this. Like by adding that view controller as childView or by presenting it to navigation controller or anything else.
The idea is that the view controller can be shown or hide from any screen of the app.

You can make a view controller as a cocoa touch class... and you can add a xib to it.. once you design the interface for the view controller..
You can make a singleton class and keep the shared instance like this:
class YourViewController: UIViewController {
static let sharedInstance = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "yourStoryBoardId")
}
To show this just do :
func someFunc() {
show(YourViewController.sharedInstance, sender: self)
}
I once did something like this in one of my apps.. i think its a standard approach.
You could also see this for more info and source

Related

iOS Top Navigation Bar

Which is the best approach in order to create a Top Navigation Bar like this one on Instagram?
I have a Tab Bar controller which has 5 views but I do not understand how to create another navigation bar inside one of this views. Should I create two labels and connect each of them with another view or is there something better to achieve this?
Your approach is good, would be nice to see some screenshots or code to fully understand it.
If you want to put navigation bar inside those tab bar views you need to put a container view that connects to a navigation controller.
I created a simple project to show you how I achieved this.
Using a scrollview to contain another two view containers embedded with some navigation controllers:
The view containers allows you to embed any type of view / controller:
Apple docs has a nice reference of how to do this, in your case you just need to change ViewController to NavigationController.
And if you don't mind to use third party code, well there are plenty of options for you to choose:
PolioPager
import PolioPager
class ViewController: MainContainerViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func tabItems()-> [TabItem] {
return [TabItem(title: "One"),TabItem(title: "Two")]
}
override func viewControllers()-> [UIViewController]
{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController1 = storyboard.instantiateViewController(withIdentifier: "cont1")
let viewController2 = storyboard.instantiateViewController(withIdentifier: "cont2")
return [viewController1, viewController2]
}
}
In above example you can use PolioPager to instantiate 2 different navigation view controllers, identified by storyboard identifier cont1 cont2 for example.
Other trip party libraries:
https://github.com/XuYanci/GLViewPagerController
https://github.com/rechsteiner/Parchment

Instantiation of ViewControllers from storyboard in Swift

I have a UIViewController that looks a bit like this:
class ProfileViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, ... {
...
convenience init(name: String) {
print("Init with student: \(name)")
self.init()
}
...
}
I have a corresponding Storyboard layout for this, embedded in a UINavigationViewController, linked to a UITabBarController. This seemed like the easiest way to design the layout, and is great for when there's only one instance of this VC required (which is how the app was originally designed).
I'd now like to create multiple tabs from this single design (between 1 and 3), and pass the VC init information programatically, but I'm unsure exactly of the best way to do this - as you can see above I've added a convenience init function based on some reading I've done as that seemed like a good place to start.
It's easy enough to create new named tabs based on the storyboard layout like this:
for user in (users)! {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "profileNC")
controller.tabBarItem.title = user.name
newTabs?.insert(controller, at: 0)
}
self.viewControllers = newTabs
But, doing it this way I don't get to call the init function to pass the UIViewController the information it needs to display correctly.
How can I create my ViewControllers, link the layout to the Storyboard and use the custom init function? Is this even possible?
Any suggestions gratefully appreciated!!
When using a storyboard you cannot use a custom initialiser. You will need to either set the property directly or use a configuration function on the view controller instance after you have created it.

Why does my ViewController still reload every time I segue to it?

The header of my HomeViewController looks like this:
private let sharedGameBoard = HomeViewController()
class HomeViewController: UIViewController, CLLocationManagerDelegate, UITextFieldDelegate {
class var sharedInstance: HomeViewController {
return self.sharedInstance
}
I have my HomeViewController embedded in a UINavigationController. To navigate to a MultipleChoiceViewController I call:
var multipleChoiceVC: MultipleChoiceViewController = self.storyboard?.instantiateViewControllerWithIdentifier("multipleChoiceViewController") as! MultipleChoiceViewController
self.navigationController?.pushViewController(multipleChoiceVC, animated: true)
To return from MultipleChoiceViewController I call a show segue that is hooked up to a swipe gesture in my main.storyboard file.
Every time I navigate from MultipleChoiceViewController to HomeViewController, HomeViewController completely reloads. How do I keep this from happening. Like is seen in so many applications, I would like to be able to navigate from detail views back to the home controller without the home controller loading each time.
My load functions are called in viewDidLoad but I have a global bool variable that indicates whether the load functions should be called or not.
I've spent a good deal of time trying to understand singletons, push/show segues, and the navigation stack, to try and alleviate what is probably a very simple thing to accomplish. What is a way to implement this?

How to Programmatically Segue to a New ViewController in a New Storyboard

I simply want to know how to segue to a new view controller in a new storyboard without having to create the new view controller programmatically.
The Scenario:
I have one view controller that's created entirely in code and the system thinks I'm in Storyboard A. I want to segue from this view controller to another view controller that's contained on Storyboard B.
I could create a segue attached to a storyboard reference (which is a great suggestion) if this view controller was created with Storyboard. But it's in code, so I can't do this.
My other option is to make the next view controller be totally created in code so that I can present it without using segues. That's a pain, but will work.
My third option is to initialize the new storyboard in code, initialize the new view controller in code using a storyboard identifier, and then use the navigation controller to segue to it.
If there are other options I'm not aware of please include them below!
This piece of code allows you to segue to any viewController anywhere in your application while still being able to build your viewController with storyboard.
func settingsButtonPressed(sender:UIButton) {
let storyboard = UIStoryboard(name: "AccountLinking", bundle: nil)
let linkingVC = storyboard.instantiateViewControllerWithIdentifier("AccountLinkingTable")
self.navigationController?.pushViewController(linkingVC, animated: true)
}
So many hours saved thanks to this little function.
I would urge anyone reading this to take a look at the Storyboard Reference introduced in Xcode 7 to achieve this instead of loading the storyboard programatically.
You can override the below function to override the segue call.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var destinationController = segue.destinationViewController
}

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