From my onboarding viewcontroller i need to transition to my tabBarController which is also a navigationController and i want to make it as a root viewcontroller afterwards.
#objc func willGoToMain(sender: UIButton!) {
let tabBarController = TabBarController()
let navigationController = UINavigationController(rootViewController: tabBarController)
navigationController.isNavigationBarHidden = true
self.present(tabBarController, animated: true, completion: nil)
}
Thread 1: "Application tried to present modally a view controller <MyStarterProject.TabBarController: 0x7f9bd8011400> that has a parent view controller <UINavigationController: 0x7f9bd7022800>
I like to transition it like a modal presentation or cross dissolve. not just to appeared as a rootviewcontroller all of a sudden.
Here's what i'm trying to do and this solves my problem.
#objc func willGoToMain(sender: UIButton!) {
guard let window = UIApplication.shared.keyWindow else {
return
}
let tabbarController = TabBarController()
let navigationController = UINavigationController(rootViewController: tabbarController)
navigationController.isNavigationBarHidden = true
window.rootViewController = navigationController
window.makeKeyAndVisible()
let options: UIView.AnimationOptions = .transitionCrossDissolve
let duration: TimeInterval = 0.3
UIView.transition(with: window, duration: duration, options: options, animations: {}, completion:
{ completed in
// maybe do something on completion here
})
}
Change this:
self.present(tabBarController, animated: true, completion: nil)
with this:
self.present(navigationController, animated: true, completion: nil)
Please try this one.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let mainTabBarController = storyboard.instantiateViewController(identifier: "MainTabBarController")
mainTabBarController.modalPresentationStyle = .fullScreen
self.present(mainTabBarController, animated: true, completion: nil)
If you need more details. please visit this blog
https://fluffy.es/how-to-transition-from-login-screen-to-tab-bar-controller/
Related
I am trying to present NavigationController and select second tab in the completion block. My code is:
let chatViewController = UITabBarController()
let navigationController = UINavigationController(rootViewController: chatViewController)
present(navigationController, animated: true, completion: {
self.visibleViewController = navigationController
self.visibleViewController?.tabBarController?.selectedIndex = 1
})
Second attempt:
let chatViewController = UITabBarController()
let navigationController = UINavigationController(rootViewController: chatViewController)
navigationController.tabBarController?.selectedIndex = 1
present(navigationController, animated: true, completion: {
self.visibleViewController = navigationController
})
In both cases tabBarController is nil. How can I switch to different tab?
You are trying to access UITabBarController of UINavigationController, but you need to access the very first controller from UINavigationController and from there you need to make your UITabBar selected like this way:
func showTabBarControllerr() {
let chatViewController = UITabBarController()
//Note: Make sure you have already added the Controllers in Tabbarcontroller
chatViewController.viewControllers = [DemoOne(), DemoTwo()]
let navigationController = UINavigationController(rootViewController: chatViewController)
present(navigationController, animated: true, completion: {
if let tabBarController = navigationController.viewControllers.first as? UITabBarController {
tabBarController.selectedIndex = 1
}
})
}
Let me know this helps or not!
Instead of calling
present(navigationController, animated: true, completion: { })
in viewDidLoad, try to call it in viewWillAppear or viewDidAppear
Try this (Swift 5):
Set an identifier to your UITabBarController in the Storyboard, something like MainTabBar
Into a function or IBAction, use this code:
let tbc = storyboard?.instantiateViewController(withIdentifier: "MainTabBar") as! UITabBarController
tbc.selectedIndex = 1 // This is the index of your controller
present(tbc, animated: false, completion: nil)
I am using dispatcQueue to automatically dismiss my controller but I have an issue is that it dismiss my view controller automatically but also dismiss other view controllers that are presented modally and I want to dismiss only a single view controller
func dismissViewController() {
let pickVc = UIStoryboard(name:"Main", bundle: nil).instantiateViewController(withIdentifier: "request-VC") as! RequestViewController
pickVc.modalPresentationStyle = .custom
pickVc.requestDelegate = self
present(pickVc, animated: true, completion: nil)
}
func openRequestAlertViewController() {
let pickVc = UIStoryboard(name:"Main", bundle: nil).instantiateViewController(withIdentifier: "requestAlertVC") as! RequestAlertViewController
pickVc.modalPresentationStyle = .custom
pickVc.searchDelegate = self
present(pickVc, animated: true, completion: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 20) {
self.dismiss(animated: true, completion: nil)
}
}
func dismissRequestVC() {
let searchVc = UIStoryboard(name:"Main", bundle: nil).instantiateViewController(withIdentifier: "searching-VC") as! SearchingViewController
searchVc.modalPresentationStyle = .custom
present(searchVc, animated: true, completion: nil)
}
but it also dismiss after 20 seconds and I don't want to dismiss this. any help? This is my whole code
Create an instance for a particular viewcontroller which you want to dismiss like the following
var lvc: LoadingViewController?
func showLoadingIn(viewController: UIViewController) {
lvc = LoadingViewController() // create new instance before presentation
viewController.presentViewController(lvc!, animated: false, completion: nil)
}
func dismissLoader() {
lvc?.dismissViewControllerAnimated(true) {
print("Dismissing Loader view Controller")
}
}
You are presenting all viewControllers with the current viewController and while dismissing you are are not dismissing the currently presented viewController. Instead you are dismissing the presenter viewController so all the presented ViewControllers are also getting dismissed.
If you want to dismiss a particular viewController you can do it like this,
yourViewController.dismiss(animated: true, completion: nil)
For example in your case you can do this to dismiss the pickVc after 20 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 20) {
pickVc.dismiss(animated: true, completion: nil)
}
I'm trying to present a view controller and dismiss my current modal view. I saw the answers on StackOverflow, but I don't understand it.
self.dismissViewControllerAnimated(true, completion: {
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("myViewController")
self.presentViewController(vc!, animated: true, completion: nil)
})
Could anyone please tell me, how to do it simply? Thanks
Check your main controller in stack and pop all other view controllers and then present new View Controller.
if let controllers = self.navigationController?.viewControllers {
for vc in controllers {
// Check if the view controller is of MainViewController type
if let myVC = vc as? MainViewController {
self.navigationController?.popToViewController(myVC, animated: false)
}
}
}
Push view controller :
let secondVC = self.storyboard?.instantiateViewController(withIdentifier: "secondVC") as! SecondViewController
self.navigationController?.pushViewController(secondVC, animated: true)
or Present View Controller :
let next = self.storyboard?.instantiateViewController(withIdentifier: "secondVC") as! SecondViewController
self.present(next as UIViewController, animated: true, completion: nil)
You can use this code to Present viewcontroller.
let yourVC = UIStoryboard(name: storyBord, bundle: nil).instantiateViewController(withIdentifier:ID) as! yourViewController
let navController = UINavigationController(rootViewController: yourVC)
self.present(navController, animated: true, completion: {
})
And for dissmissing use this in your presented viewController
self.dismiss(animated: true, completion: {
})
My goal is to present a UIViewController as a popover programmatically.
As you can see , the transition style is set to Cross Dissolve and the presentation is set to Over current context. So technically if I click the button, the transition will work, my goal is to do it programmatically.
func clickButton() {
//What should I do here?
}
How do I present the popover programmatically on clickButton?
If you are presenting view controller modally. You can do like this.
func clickButton() {
if let vc = self.storyboard?.instantiateViewController(withIdentifier:"YOUR_VIEW_CONTROLLER_ID") {
vc.modalTransitionStyle = .crossDissolve;
vc.modalPresentationStyle = .overCurrentContext
self.present(vc, animated: true, completion: nil)
}
}
You can try this:
let rateViewController = RatePopupVC()
rateViewController.modalTransitionStyle = .crossDissolve
rateViewController.modalPresentationStyle = .overCurrentContext
self.present(rateViewController, animated: true, completion: nil)
If you want to close it programmatically
Inside PopupVC
self.dismiss(animated: true, completion: nil)
Try this :
func clickButton() {
let vc : PopupVC = storyboard!.instantiateViewControllerWithIdentifier("PopupVCID") as! PopupVC
vc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
self.presentViewController(vc, animated: true, completion: nil)
}
Try following code.
let popupview = storyboard?.instantiateViewController(withIdentifier: "YourViewController")
popupview.view.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
self.addChildViewController(popupview)
self.view.addSubview(popupview.view)
popupview.didMove(toParentViewController: popupview)
I had referred to this question and several question about view / view controller transition but still couldn't find an satisfied answer. Most of the solutions suggest to flip the views instead of view controllers. However, the two view controllers in my app have totally different operation and implementation logic, thus I'm avoiding to mix them together.
In my app, I have a modal view controller FrontViewController which is embedded in a NavigationController. After pushing one button on the view, the modal view controller should flip to BackViewController, and vice versa. I had ever tried the following in FrontViewController:
let navi = UINavigationController(rootViewController: backController)
navi.modalPresentationStyle = .CurrentContext
navi.modalTransitionStyle = .FlipHorizontal
self.presentViewController(backController, animated: true, completion: nil)
This works almost as what I want, except that it flips navigation bar as well. Moreover, if I dismiss the modal view, only the view controller on the top of the stack is dismissed, while I failed to get the right parent/presenting controller to dismiss all the other stack controllers in the modal view.
Thus I further tried to prevent viewcontroller stack and use transitionFromViewController in FrontViewController using the same navigation controller instead:
self.navigationController!.addChildViewController(backController)
self.willMoveToParentViewController(nil)
self.navigationController!.transitionFromViewController(self, toViewController: backViewController, duration: 1, options: .TransitionFlipFromLeft, animations: {}, completion: ({Bool -> Void in
self.removeFromParentController()
c.didMoveToParentViewController(self)
}))
Then I got this run time error on executiing: Parent view controller is using legacy containment in call to -[UIViewController transitionFromViewController:toViewController: duration:options:animations:completion:]
So, how to transition between two view controllers while preventing them remain in the view controller stack?
You can add custom transition to the navigation controllers layer just before pushing the view controller.
let transition = CATransition()
transition.duration = 0.3
transition.type = "flip"
transition.subtype = kCATransitionFromLeft
self.navigationController?.view.layer.addAnimation(transition, forKey: kCATransition)
self.navigationController?.pushViewController(viewController!, animated: false)
Note that the animated parameter should be false. Otherwise the default sliding animation will takes place
See this demo for you :
Swift code for flipAnimation :
let mainStory = UIStoryboard(name: "Main", bundle: nil)
let search = mainStory.instantiateViewControllerWithIdentifier("SecondViewController") as! SecondViewController
UIView.beginAnimations("animation", context: nil)
UIView.setAnimationDuration(1.0)
self.navigationController!.pushViewController(search, animated: false)
UIView.setAnimationTransition(UIViewAnimationTransition.FlipFromLeft, forView: self.navigationController!.view, cache: false)
UIView.commitAnimations()
FlipViewController Animation
Output :
Swift 5 - I personally like using this approach.
//PUSH
let secondVC = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "secondVC") as! SecondVC
self.navigationController?.pushViewController(secondVC, animated: false)
UIView.transition(from: self.view, to: secondVC.view, duration: 0.85, options: [.transitionFlipFromLeft])
//POP
let firstVC = self.navigationController?.viewControllers[(self.navigationController?.viewControllers.count ?? 2) - 2] as? FirstVC
if let firstView = firstVC?.view{
self.navigationController?.popViewController(animated: false)
UIView.transition(from: self.view, to: firstView, duration: 0.85, options: [.transitionFlipFromRight])
} else {
self.navigationController?.popViewController(animated: true)
}
Swift 3.0 +
Should use UIView's animation block, make sure your viewController in UINavigationController stacks:
let viewController = ViewController(nibName: "xxx", bundle: nil)
UIView.transition(with: self.navigationController!.view, duration: 1.0, options: .transitionFlipFromLeft, animations: {
self.navigationController?.pushViewController(viewController, animated: false)
}, completion: nil)
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
// for back button
changeTransition()
}
//btnMap.addTarget(self, action: #selector(searchHotelsResultVC.goToMap), for: .touchUpInside)
//btnMap.addTarget(self, action: #selector(MapViewController.backToList), for: .touchUpInside)
func goToMap() {
// for pushing
changeTransition()
navigationController?.pushViewController(settingsVC, animated: false)
}
func backToList() {
// for dismiss
changeTransition()
navigationController?.popViewController(animated: false)
dismiss(animated: true, completion: nil)
}
func changeTransition() {
let transition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
//transition.type = kCATransitionPush
transition.type = "flip"
transition.subtype = kCATransitionFromLeft
navigationController?.view.layer.add(transition, forKey: kCATransition)
}
here Student is NSObjectClass
var Arraydata:[Student] = []
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let arr = Arraydata[indexPath.row]
if indexPath.row == arr
{
let story = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
UIView.beginAnimations("", context: nil)
UIView.setAnimationDuration(1.0)
UIView.setAnimationCurve(UIViewAnimationCurve.easeInOut)
UIView.setAnimationTransition(UIViewAnimationTransition.flipFromRight, for: (self.navigationController?.view)!, cache: false)
self.navigationController?.pushViewController(story, animated: true)
UIView.commitAnimations()
}
}