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.
Related
I'm working on a project, the project doesn't have storyboards, it just have a views as xib files with its own class , the question is : how can I navigate between these xib views ?
or is it possible to embed them in navigation controller ?
I try this code but nothing happened ?
let NC = UINavigationController()
#IBAction func showUserProfile(_ sender: Any) {
print("show Profile")
let vc = UserProfile(
nibName: "UserProfile",
bundle: nil)
NC.pushViewController(vc,
animated: true )
}
this is in app delegate
let mainView = BlockListViewController(nibName: "BlockListViewController", bundle: nil)
window?.addSubview(mainView)
let navigationControll = UINavigationController(rootViewController: mainView)
self.window?.rootViewController = navigationControll
self.window?.makeKeyAndVisible()
and I try to navigate when event occur using this
self.navigationController?.pushViewController(UserProfile(), animated: true)
You can't navigate between instances of UIView
according to apple UINavigationController
A container view controller that defines a stack-based scheme for navigating hierarchical content.
A navigation controller is a container view controller that manages
one or more child view controllers
so basically a stack of UIViewController, defined as [UIViewController]
read more about it in the documentation
What you can do is adding each UIView in a UIViewController and navigate thru that simply.
According to your comment you can predefined them into instance of VC and create a UINavigationController with you'r initial then simply push to the desired UIViewController from the UINavigationController
COMMENT UPDATE
As I got from your comment in the main view you already defining the UINavigationController simply replace NC.pushViewController(vc,animated: true )
with self.navigationController.pushViewController(vc, animated: true )
The problem is you are creating new UINavigationController while you already have the first one embedded
Comment update:
if you're using iOS 13+ with scene delegate use this inside willConnectTo
guard let scene = (scene as? UIWindowScene) else { return }
// Instantiate UIWindow with scene
let window = UIWindow(windowScene: scene)
// Assign window to SceneDelegate window property
self.window = window
// Set initial view controller from Main storyboard as root view controller of UIWindow
let mainView = BlockListViewController(nibName: "BlockListViewController", bundle: nil)
let navigationControll = UINavigationController(rootViewController: mainView)
self.window?.rootViewController = navigationControll
// Present window to screen
self.window?.makeKeyAndVisible()
and call self.navigationController.push
like this
#IBAction func didTap(_ sender: UIButton) {
let secondView = secondVC(nibName: "secondVC", bundle: nil)
self.navigationController?.pushViewController(secondView, animated: true)
}
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) {
}
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 :)
I'm basically trying to create a custom UITabBarController since I need some specific functionality. The TabBar itself is done and working, but I don't quite know how to display ViewControllers in this CustomTabBarViewController itself.
Assuming i have the following method:
func tabSelected(_ index: Int) {}
and knowing the height of my TabBar through tabbar.frame.size, how do I instantiate two ViewControllers above the TabBar and switch between them when the tabSelected method is called? A transition animation would be even nicer, but not really necessary.
NOTE: my TabBar doesn't inherit from UITabBarController, only from the regular UIViewController, to avoid further confusion.
Here I created sample project:
CustomTabBarViewController
You should have container view for child ViewControllers
Then you should have array with embed ViewControllers
You should call method in
CustomTabBarViewController which change ViewController inside
container view to ViewController from array of VCs at index which you pass as parameter of this method
Start with declaring outlet collection for your TabBar buttons and also get reference for container view where your ViewControllers will be showed
#IBOutlet var tabBarButtons: [UIButton]!
#IBOutlet weak var container: UIView!
then create array for your tab bar items
var items: [UIViewController]?
next create lazy variables for your controllers
private lazy var aVC: A = {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
return storyboard.instantiateViewController(withIdentifier: "a") as! A
}()
private lazy var bVC: B = {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
return storyboard.instantiateViewController(withIdentifier: "b") as! B
}()
.... this can be simplified by creating method which returns ViewController depending on VC’s identifier
After that append ViewControllers to your items array and also each add as child of your TabBarViewController
override func viewDidLoad() {
super.viewDidLoad()
items = [aVC, bVC]
items!.forEach { addChild($0) }
}
continue with declaring method for setting ViewController
private func setViewController(_ viewController: UIViewController) {
items!.forEach { $0.view.removeFromSuperview(); $0.willMove(toParent: nil) }
container.addSubview(viewController.view)
viewController.view.frame = container.bounds
viewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
viewController.didMove(toParent: self)
}
now add action for your tab bar buttons and get index of button. Then with this index call your tabSelected method
#IBAction func buttonPressed(_ sender: UIButton) {
if let index = tabBarButtons.index(of: sender) {
tabSelected(index)
}
}
inside tabSelected set VC from items depending on index of sender tab bar button
func tabSelected(_ index: Int) {
if let item = items?[index] {
setViewController(item)
}
}
finally in viewDidLoad set first item
override func viewDidLoad() {
...
tabSelected(0)
}
Now you can fully customize your ViewController and make other epic stuff which you know from UITabBarController
Here's another approach:
1. In your CustomTabBarViewController define an array to hold the ViewControllers:
var viewControllers: [UIViewController]
Instantiate the view controllers and add them to the array:
// If you're not using storyboard:
let homeViewController = HomeViewController()
// If using storyboard:
let searchViewController = storyboard.instantiateViewController(withIdentifier: "SearchViewController")
viewControllers = [homeViewController, searchViewController, ...]
2. Define a variable to keep track of the tab button that is selected:
var selectedIndex: Int = 0
3. Implement your tabSelected method like so. I've explained each line in code:
func tabSelected(_ index: Int) {
let previousIndex = selectedIndex
selectedIndex = index
// Use previousIndex to access the previous ViewController from the viewControllers array.
let previousVC = viewControllers[previousIndex]
// Remove the previous ViewController
previousVC.willMove(toParentViewController: nil)
previousVC.view.removeFromSuperview()
previousVC.removeFromParentViewController()
// Use the selectedIndex to access the current ViewController from the viewControllers array.
let vc = viewControllers[selectedIndex]
// Add the new ViewController (Calls the viewWillAppear method of the ViewController you are adding)
addChildViewController(vc)
vc.view.frame = contentView.bounds
// contentView is the main view above your tab buttons
contentView.addSubview(vc.view)
// Call the viewDidAppear method of the ViewController you are adding using didMove(toParentViewController: self)
vc.didMove(toParentViewController: self)
}
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 .