Set initial viewController in Navigation controller programmatically (Layer SDK) - ios

I want to add Layer SDK to my application (using Swift).
All view controllers here are created programmatically. Therefore I can't segue to them. I have 4 tabs in my application (UITabBarController). One of them is chat. In the chat tab I created a segue to UINavigationController. Now I want to load conversationListViewController in this UINavigationController. For that I created a class for this UINavigationController i.e. ConversationListViewController and added the following code:
class ChatNavigationViewController: UINavigationController {
var conversationListViewController: ConversationListViewController!
var layerClient: LYRClient!
override func viewDidLoad() {
let appDelegate = UIApplication.sharedApplication().delegate as!AppDelegate
self.layerClient = appDelegate.layerClient
self.conversationListViewController = ConversationListViewController(layerClient: appDelegate.layerClient)
self.conversationListViewController.displaysAvatarItem = true
self.navigationController!.pushViewController(self.conversationListViewController, animated: true)
}
}
But this is not working. And giving this kind of effect: the ConversationViewController is not loaded in UINavigationController. I am not sure if I am doing it the correct way. I'm searching for the correct way, but unable to find.

I Solved it. I dragged new NavigationViewController and added ConversationListViewController to rootviewController.I think i should try this first. Anyways thanks guys for your help.

Because you want to do this programatically:
You need to manually initialize the controller before stacking it up on the Navigation Controller. Try this:
navigationController?.pushViewController(self.conversationListViewController.init(), animated: true)

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

TabBarController behind the scenes and correct approach for code behind

Just imagine( as case) that i have TabBarController as root and several ViewControllers that are linked to this TabBarController( via Storyboard(!) that is important step,i mean programmatically it's something other).
And its works without any code behind on TabBarController class!
So i'm interested in right approach, how can i Inistiate Viewcontrollers inside TabBarController on right way!?
Or it's isn't necessary and OS will do it for me , because at current moment, i can do something like this :
public override void ViewDidLoad()
{ //No Init for VC that are inside linked to TabBAr
base.ViewDidLoad();
//Find all viewcontrollers that are linked in storyboard
foreach (var Item in ViewControllers)
{
Item.TabBarItem.Image =
UIImage.FromBundle("RandomImg");
//Change title for all VC to "Main"
Item.TabBarItem.Title = "Main";
break;
}
}
What if i will do initialization of ViewControllers inside TabBarController constructor.
What will be happened on behind the scenes? How the system will recognize my init of VC,or it's doesn't matter and thats will be an redundant action, because technique via storyboard anyway creates ViewControllers without any initialization on code behind!?
How to handle/customize correctly ViewControllers that are inside of TabBarController?(e.g. select another VC at beginning, change buttons on TabBar and etc)
I would like to take all answers on all my questions and if it possible, need an live example/article that explains more advanced about this stuff. Thanks!

childViewControllers is empty after calling addChildViewController

I have a question regarding add/remove childviewcontrollers with ContainerView.
I have a UIViewController named "ContainerViewController" that contains a ContainerView, and this ContainerView has a UIViewController named "ContainerLinkViewController". I also have four other UIViewControllers that will be added to or removed from this "ContainerLinkViewController" whenever user a clicks one of the tab button that is placed at the bottom of "ContainerViewController". The storyboard looks like below.
NOTE that the custom segues connected to those four UiViewcontrollers are just empty segue that does nothing but show visual connection in storyboard.
So what I do is first add the First Tab ViewController to "ContainerLinkViewController" as a childViewController by using below code in viewDidLoad().
let firstTabViewController = self.storyboard?.instantiateViewController(withIdentifier: "FirstTabViewController") as! FirstTabViewController
self.addChildViewController(firstTabViewController)
firstTabViewController.view.frame = self.view.bounds
self.view.addSubview(firstTabViewController.view)
firstTabViewController.didMove(toParentViewController: self)
After this initial setup, whenever user tabs on one of those tab buttons, I send signal from "ContainerViewController" that which UIViewController is to be added as new childViewController to "ContainerLinkViewController" and switching the old childViewController and this new childViewController using the below code.
func swapViewControllers(from : UIViewController, to : UIViewController) {
from.willMove(toParentViewController: nil)
self.addChildViewController(to)
to.view.frame = self.view.bounds
self.transition(from: from, to: to, duration: 1.0, options: UIViewAnimationOptions.transitionCrossDissolve, animations: nil) {
finished in
from.view.removeFromSuperview()
from.removeFromParentViewController()
to.didMove(toParentViewController: self)
}
}
Before calling this "swaptViewControllers()", I take the old childViewController by doing the following.
let oldChildViewController = self.childViewControllers.last
My problem is that this "oldChildViewController" is nil when I click one of those tabs for the first time right after the initial setup. So the function "swaptViewControllers()" does not even called because the self.childViewControllers is empty.
I have been struggling with this for few days now and could not find clear answer to solve this. So I decided to ask here to get some help about what might cause this.
Any help?? Thanks.
NOTE : I am using swift 3. Maybe this would help to answer my question since it seems lots of things changed fro swift 2.

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