Switch Between Child View Controllers - ios

I have a view controller that contains multiple container views, we will call it HomeViewController. I declare these container views (childViewControllers) as so (each one is a Container View with its own embeded viewController:
private lazy var startContactViewController: StartContactViewController = {
//Load Storyboard
let storybaord = UIStoryboard(name: "Main", bundle: Bundle.main)
//Instantiate View Controller
var viewController = storyboard?.instantiateViewController(withIdentifier: "StartContact") as! StartContactViewController
//Add View Controller as Child View Controller
self.add(asChildViewController: viewController)
return viewController
}()
private lazy var stopContactViewController: StopContactViewController = {
//Load Storyboard
let storybaord = UIStoryboard(name: "Main", bundle: Bundle.main)
//Instantiate View Controller
var viewController = storyboard?.instantiateViewController(withIdentifier: "StopContact") as! StopContactViewController
//Add View Controller as Child View Controller
self.add(asChildViewController: viewController)
return viewController
}()
private lazy var startDayViewController: StartDayViewController = {
//Load Storyboard
let storybaord = UIStoryboard(name: "Main", bundle: Bundle.main)
//Instantiate View Controller
var viewController = storyboard?.instantiateViewController(withIdentifier: "StartDay") as! StartDayViewController
//Add View Controller as Child View Controller
self.add(asChildViewController: viewController)
return viewController
}()
private lazy var loadingViewController: LoadingViewController = {
//Load Storyboard
let storybaord = UIStoryboard(name: "Main", bundle: Bundle.main)
//Instantiate View Controller
var viewController = storyboard?.instantiateViewController(withIdentifier: "loading") as! LoadingViewController
//Add View Controller as Child View Controller
self.add(asChildViewController: viewController)
return viewController
}()
I then have these 2 functions to add and remove the childViewControllers:
func add(asChildViewController viewController: UIViewController) {
//Add Child View Controller
addChildViewController(viewController)
//Add Child View as Subview
view.addSubview(viewController.view)
//Configure Child View
viewController.view.frame = view.bounds
viewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
//Notify Child View Controller
viewController.didMove(toParentViewController: self)
}
func remove(asChildViewController viewController: UIViewController) {
// Notify Child View Controller
viewController.willMove(toParentViewController: nil)
// Remove Child View From Superview
viewController.view.removeFromSuperview()
// Notify Child View Controller
viewController.removeFromParentViewController()
}
When my app first loads the StartDayViewController is presented. Within this view controller their is a button. When the users presses that button I would like the StartDayViewController to be removed and the StartContactViewController to be presented. How can I achieve this from the StartDayViewController?
I have also included a picture of the storyboard.
Storyboard image

You can do it using protocol
protocol StartVcProtocol {
func startButtonPressed()
}
Let HomeViewController implement it
extension HomeViewController: StartVcProtocol {
func startButtonPressed() {
// start button pressed -- do your remove and add stuff here
}
}
Now in StartVc
class StartVc: UIViewController {
var delegate: StartVcProtocol?
//inside you start button iBaction
delegate?.startButtonPressed()
}
Then when lazy initializing the StartVc
viewController.delegate = self
Hope you get all the pieces .

Related

Loading a ViewController from nib file owner

I have a design made in nib and in round about all ViewControllers I am loading that nib design.
Now as that was common footer so I managed to used it in the footer of all other view controllers.
Now what I want : I want that whenever User click on a footer it must start a new View Controller that will show what you can say "About us " view controller.
What I am doing:
// ON CLICK OF FOOTER I AM DOING
let mAboutUs = self.storyboard?.instantiateViewController(withIdentifier: "idAboutUs") as! AboutUs
mAboutUs.modalPresentationStyle = .fullScreen
self.present(mAboutUs, animated: true) {
}
but I am getting following error
Value of type 'FooterView' has no member 'storyboard'
My Understanding: I think from nib file we can not start a new ViewController, But I really do not want to do this thing in all other View controllers in which I added this nib (FooterView) as my footer view at bottom of each view controller.
Please help me!!!!
A UIView subclass doesn't contain a storyboard property it's for a vc subclass , You need
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "idAboutUs") as! AboutUs
if you want to present a vc from inisde the view FooterView then add a delegate like
weak var delegate:VCName?
When you create an instance
let ins = FooterView() // or from storyboard
ins.delegate = self
Then use
delegate?.present(mAboutUs, animated: true)
inside the view's class
You can use a delegate that all vcs conforms to but the easiest is to add this extension
extension UIViewController {
func topMostViewController() -> UIViewController {
if let presented = self.presentedViewController {
return presented.topMostViewController()
}
if let navigation = self as? UINavigationController {
return navigation.visibleViewController?.topMostViewController() ?? navigation
}
if let tab = self as? UITabBarController {
return tab.selectedViewController?.topMostViewController() ?? tab
}
return self
}
}
Then
guard let currentVC = (UIApplication.shared.delegate as! AppDelegate).window?.rootViewController.topMostViewController() else { return }
currentVC.present(mAboutUs, animated: true)
Your code should look similar to this:
let vc = UIStoryboard(name: "<Name of the storyboard that contains the About Us VC>", bundle: nil).instantiateViewController(withIdentifier: "idAboutUs") as! AboutUs
self.present(vc, animated: true) {
}

how to manage which controller should show in parent view controller?

I have a parent view controller with 5 container view as you can see in image :
but when I run my app ,all child view controllers are shown blow by blow and they dismiss and goes back to my starter view controller (which is initial view controller and I push my parent navigation controller form it).
I want to know how to prevent it and how to show my first view controller when parent view controller showed ?
I don't know what is wrong with storyboard but my problem was :
because I adde 5 container view to my main view controller and connected all of them to their view controllers by segue it presents all of them and then close main view controller .
I clean all segue and container views from storyboard and I did it like this :
private lazy var firstViewController: AvailableView = {
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
var viewController = storyboard.instantiateViewController(withIdentifier: "AvailableViewID") as! AvailableView
self.add(asChildViewController: viewController)
return viewController
}()
private lazy var secondViewController: NotificationView = {
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
var viewController = storyboard.instantiateViewController(withIdentifier: "NotificationViewID") as! NotificationView
self.add(asChildViewController: viewController)
return viewController
}()
private func add(asChildViewController viewController: UIViewController) {
addChild(viewController)
view.addSubview(viewController.view)
viewController.view.frame = view.bounds
viewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
viewController.didMove(toParent: self)
}
private func remove(asChildViewController viewController: UIViewController) {
viewController.willMove(toParent: nil)
viewController.view.removeFromSuperview()
viewController.removeFromParent()
}
and the way you can use it :
in viewDidLoad():
add(asChildViewController: firstViewController)
and when you wanted to present second view controller you should remove first View Controller and then add your second view controller like so:
remove(asChildViewController: firsttViewController)
add(asChildViewController: secondViewController)
you can see this link for more explanation : https://cocoacasts.com/managing-view-controllers-with-container-view-controllers/
hope to help any one else :)

Modifying SwipeViewController Pod to run in a ContainerView

So im using this pod 'SwipeViewController' (https://github.com/fortmarek/SwipeViewController) that really gives me the effect that I want but the problem is that it only runs as the main navigation controller and I want it to work in a container view because I want to use it for this social app in the profile menu like twitter does with "My Tweets", "Likes", "Repost"...
so for example I need this...
https://camo.githubusercontent.com/f4eb2a8ba0a11e672d02a1ef600e62b5272a7843/687474703a2f2f696d6775722e636f6d2f5344496b6634622e676966
to work in here:
So just an explanation, to make the pod work you need to add this line of code to the appDelegate
let pageController = UIPageViewController(transitionStyle: .Scroll, navigationOrientation: .Horizontal, options: nil)
let navigationController = YourViewControllerName(rootViewController: pageController)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
wich creates a new window with the SwipeController, I need a way to make it work in a View controller.
I did something similar last night using the tutorial here:
https://cocoacasts.com/managing-view-controllers-with-container-view-controllers/
My associated code is below. I created an IBOutlet from the container view to my ViewController and then the code below adds the appropriate view controller to the container view depending on the setting of my Bool called buttonDefault. Make sure to add the child view to your container view and not the main view from the view controller.
#IBOutlet weak var containerView: UIView!
// MARK: Container View
// https://cocoacasts.com/managing-view-controllers-with-container-view-controllers/
lazy var remoteViewController: RemoteViewController = {
// Load Storyboard
let storyboard = UIStoryboard(name: "MainStoryboard", bundle: nil)
// Instantiate View Controller
var viewController = storyboard.instantiateViewController(withIdentifier: "RemoteViewController") as! RemoteViewController
// Add View Controller as Child View Controller
self.add(asChildViewController: viewController)
return viewController
}()
lazy var gestureRemoteViewController: GestureRemoteViewController = {
// Load Storyboard
let storyboard = UIStoryboard(name: "MainStoryboard", bundle: nil)
// Instantiate View Controller
var viewController = storyboard.instantiateViewController(withIdentifier: "GestureRemoteViewController") as! GestureRemoteViewController
// Add View Controller as Child View Controller
self.add(asChildViewController: viewController)
return viewController
}()
func add(asChildViewController viewController: UIViewController) {
// Add Child View Controller
addChildViewController(viewController)
// Add Child View as Subview
containerView.addSubview(viewController.view)
// Configure Child View
viewController.view.frame = containerView.bounds
viewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// Notify Child View Controller
viewController.didMove(toParentViewController: self)
}
func remove(asChildViewController viewController: UIViewController) {
// Notify Child View Controller
viewController.willMove(toParentViewController: nil)
// Remove Child View From Superview
viewController.view.removeFromSuperview()
// Notify Child View Controller
viewController.removeFromParentViewController()
}
func updateView() {
let settings = Settings()
if settings.buttonDefault {
remove(asChildViewController: gestureRemoteViewController)
add(asChildViewController: remoteViewController)
} else {
remove(asChildViewController: remoteViewController)
add(asChildViewController: gestureRemoteViewController)
}
}
Once you add this just call updateView() in your viewDidLoad and any time the user selects a new option to view.
I hope this helps.

How to remove a VC then add another VC directly afterward

I have a Main VC (call this VC A), that has a child VC (VC B). When I tap a button on VC B I dismiss it as a child VC, however once this is done I would like to instantiate another VC (VC C). I do this by creating a bool on VC B which, if true calls a function on VC A that creates a new child VC (VC C). All of the function calls are being made however the VC C never gets added. Below I have added the code:
VC B:
func removeAnimate()
{
self.willMove(toParentViewController: nil)
self.view.removeFromSuperview()
self.removeFromParentViewController()
didTransition = true
if didTransition == true {
callAddVC()
}
}
func callAddVC() {
let instVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "MainViewController") as! MainViewController
instVC.addVC()
}
VC A:
func addVC () {
let popvc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "CommentsTabViewController") as! CommentsTabViewController
self.addChildViewController(popvc)
popvc.view.center = self.view.center
popvc.view.bounds.size = CGSize(width: 337, height: 503)
self.view.addSubview(popvc.view)
popvc.didMove(toParentViewController: self)
}
You are creating new instance of ViewController A (MainViewController) on the callAddVC(), Which is wrong. You are not using existing instance of the ViewController A
You have to pass the Viewcontroller A instance while adding a Viewcontroller B
Viewcontroller A
let viewControllerB = // Get the instance of UIViewControllerB from storyboard
viewControllerB.vcA = self
Viewcontroller B
class UIViewControllerB {
weak var vcA: UIViewControllerA?
func removeAnimate() {
self.willMove(toParentViewController: nil)
self.view.removeFromSuperview()
self.removeFromParentViewController()
didTransition = true
if didTransition == true {
vcA.addVC(). //You have to call addVC() by using the reference of the main view controller.
}
}
}
let instVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "MainViewController") as! MainViewController
This line creates (instantiates) a NEW instance of your MainViewController, it is not your current, displayed MainViewController.
You need to maintain a reference to the first MainViewController (possibly by accessing the rootViewController on the main window. And add the new popover to that.

How to navigate To a ViewController From xib file of a UIView Class

I have a view in my xib file which contain buttons. i want to move to a ViewController when i will press the button (#IBAction). I have used below code
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("About") as! AboutViewController
self.presentViewController(nextViewController, animated: true, completion: nil)
I am getting the error "Value of type 'SlideMenuView' has no member 'presentViewController'.
because my class is a UIView type :
class SlideMenuView: UIView {
}
so how can I navigate to other view controller.
That is beacuase the class you are trying to present from is a UIView and not a UIViewController. It has no Present method.
I'm guessing your view (SlideMenuView) is embedded inside a viewcontroller. what you need to do is implement a delegate, and inform your containing viewController to present next Viewcontroller.
code below:
#protocol SlideMenuViewDelegate: class {
func slideMenuViewAboutButtonClicked(menuView: SlideMenuView)
class SlideMenuView: UIView {
weak var delegate: SlideMenuViewDelegate?
#IBAction func aboutButtonClicked(sender: AnyObject) {
self.delegate?.slideMenuViewAboutButtonClicked(self)
}
now, in your viewController, implement this delegate method:
func slideMenuViewAboutButtonClicked(menuView: SlideMenuView) {
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("About") as! AboutViewController
self.presentViewController(nextViewController, animated: true, completion: nil)
}
Also, dont forget to assign the sliderMenuView object the viewcontroller as a delegate.
something like:
self.sliderMenuView.delegate = self // (self == the containing viewController
I did it in a different way. In class file
class SlideMenuView: UIView {
var navigationController: UINavigationController? // Declare a navigation controller variable
// And create a method which take a navigation controller
func prepareScreen(navController: UINavigationController)-> UIView {
navigationController = navController
let nibView = NSBundle.mainBundle().loadNibNamed("SlideMenuView", owner: self, options: nil)[0] as! UIView
self.addSubview(nibView)
return nibView
}
// In Button action
#IBAction func btnAction(sender: UIButton) {
var storyBoard = UIStoryboard(name: "Main", bundle: nil)
let nextViewController = storyBoard!.instantiateViewControllerWithIdentifier("NextViewController") as! UIViewController
navigationController?.pushViewController(nextViewController, animated: true)
}
}
// For calling from UIViewController
slideBarMenuIstance.prepareScreen(self.navigationController!)

Resources