I have a navigation bar in my application that I change the navigation to present modally But I want when user goes to the destination view controller the navigation animation from left to right
here is my codes in the first view controller
#IBAction func showProfilePage(_ sender: UIBarButtonItem) {
self.performSegue(withIdentifier: "showprofile", sender: self)
}
I read apple site for this and use this function too
private func navigationController(_ navigationController: UINavigationController,
willShow viewController: ProfileViewController,
animated: Bool) {
}
But it doesn't work so what should I do to change navigation animation from left to right?
Try this.
let storyBoard : UIStoryboard = UIStoryboard(name: "PatientCheckout", bundle:nil)
let controller = storyBoard.instantiateViewController(withIdentifier: "PatientCheckoutViewController") as UIViewController
let transition = CATransition.init()
transition.duration = 0.45
transition.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionDefault)
transition.type = kCATransitionPush //Transition you want like Push, Reveal
transition.subtype = kCATransitionFromLeft // Direction like Left to Right, Right to Left
transition.delegate = self
view.window!.layer.add(transition, forKey: kCATransition)
self.navigationController?.pushViewController(controller, animated: true)
Related
Inside my app I have a MainVC. From there I present another ViewControllerB and I would like to push inside there so this is how I achieve this:
let ViewControllerB = self.storyboard?.instantiateViewController(withIdentifier: "ViewControllerB") as! ViewControllerB
let navController = UINavigationController(rootViewController: communityVC)
self.present(navController, animated: true, completion: nil)
This is working exactly how I want it to work. However in
ViewControllerB I also would like to push a certain ViewControllerC full screen from bottom and NOT just inside the modalView. I am calling this:
let firstLaunchVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "FirstLaunchVC")
let transition:CATransition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromTop
self.navigationController?.modalPresentationStyle = .fullScreen
self.navigationController!.view.layer.add(transition, forKey: kCATransition)
self.navigationController?.pushViewController(firstLaunchVC, animated: true)
This is pushing from the bottom but NOT fullscreen. I also get this message in the terminal:
Setting modalPresentationStyle once <UINavigationController: 0x1060f2a00> has been presented will have no effect until it is dismissed and presented again.
How can I push fullscreen from a presented ViewController?
I hope I made my problem clear. Let me know if you need more information on something.
Coordinator for transition - UINavigationControllerDelegate
Create a simple class that will conform to UINavigationControllerDelegate, I won't get into details but the main method which is the answer for your question is navigationController(_:animationControllerFor:from:to:)
Inside body of this method you can retrieve the operation which is being performed (push, pop...), additionally you can make a decision for animator based upon the view controllers (from, to).
In case you want default animator just return nil.
Example
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
switch operation {
case .push: // For push method
return YourCustomAnimator() //Conforming to `UIViewControllerAnimatedTransitioning`
case .pop:
return nil // For pop we want default animation
// I skipped the default case
}
// CASE 2
// Or for example you want to make custom animation only for specific view controller
if toVC is SpecialViewController {
return YourCustomAnimator()
}
return nil // for the rest use default animation
}
I fixed it by calling this:
let navigationController = UINavigationController(rootViewController: firstLaunchVC)
navigationController.modalPresentationStyle = .fullScreen
present(navigationController, animated: true)
This is working exactly how I want it to work, even though I am not quite sure if I am messing up my ViewController-Hirarchy... anyway it is working :D thanks for the help
So when I click on a button from another View Controller, it is suppose to present the next View Controller. However, when clicking the button, it just show the next View Controller with a black screen, even though there is content on it. How do I fix this?
I do know that there had already been similar questions asked but none helped me in solving this issue.
Button clicked code:
#IBAction func onSignUp(_ sender: Any) {
presentDetail(SignUpViewController())
}
Present next View Controller and animation code:
extension UIViewController {
func presentDetail(_ viewControllerToPresent: UIViewController) {
let transition = CATransition()
transition.duration = 0.25
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromRight
self.view.window!.layer.add(transition, forKey: kCATransition)
self.present(viewControllerToPresent, animated: false)
}
func dismissDetail() {
let transition = CATransition()
transition.duration = 0.25
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromLeft
self.view.window!.layer.add(transition, forKey: kCATransition)
dismiss(animated: false)
}
}
To clarify, the presentDetail function suppose to present the next View Controller with an animation (From Right), as shown in the code.
You need to instantiate the target ViewController from Storyboard before presenting it.
#IBAction func onSignUp(_ sender: Any) {
presentDetail(
storyboard?.instantiateViewController(withIdentifier: "putyourIdentifierhere"))
}
instantiateViewController function returns the Viewcontroller you want to present.
I am presenting a view controller after pushing another view controller with animation as my application requires it. The code is as given below:
func pushViewController() {
let viewcontroller = UIStoryboard(name: "Home", bundle: nil).instantiateViewController(withIdentifier: "homeSearchIndentifier") as? HomeSearchViewController
let searchViewController = UIStoryboard(name: "Home", bundle: nil).instantiateViewController(withIdentifier: "searchRideIdentifier") as? SearchRideViewController
searchViewController?.parentView = .homeLandingPage
let duration = 0.4
let transition: CATransition = CATransition()
transition.duration = duration
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromBottom
self.navigationController!.view.layer.add(transition, forKey: kCATransition)
self.navigationController?.pushViewController(viewcontroller!, animated: false)
viewcontroller?.present(searchViewController!, animated: true, completion: nil)
}
In the presented view controller i am assigning a Side Menu controller as i need to show the side menu while swiping to the right:
override func viewDidLoad() {
super.viewDidLoad()
self.addSearchListScreen()
self.locationManager.delegate = self
yourLocation.layer.sublayerTransform = CATransform3DMakeTranslation(7, 0, 0)
let leftViewController = UIStoryboard(name: "SideBar", bundle: nil).instantiateViewController(withIdentifier: "sideBar") as? SideBarViewController
let slideMenuController = SlideMenuTrackerController(mainViewController: self, leftMenuViewController: leftViewController!)
AppDelegate.sharedInstance().window?.rootViewController = slideMenuController
leftViewController?.mainViewController = self
slideMenuController.automaticallyAdjustsScrollViewInsets = true
AppDelegate.sharedInstance().window?.backgroundColor = UIColor(red: 236.0, green: 238.0, blue: 241.0, alpha: 1.0)
AppDelegate.sharedInstance().window?.makeKeyAndVisible()
}
Now i have a custom back button in this view controller. On clicking it i need to dismiss the view controller and show the view controller from where it was presented . The name is "HomeSearchViewController"
For dismissing i wrote the following code in the button action:
func navigateToPreviousController() {
self.dismiss(animated: true, completion: nil)
}
But this is not dismissing the view controller. May i know what is the issue?
in order to dismiss the view controller your view controller should be embedded inside a navigation controller.
eg:
let controller =storyboard.instantiateViewController(withIdentifier: "storyboardidentifier") as! yourviewcontroller
let navController = UINavigationController(rootViewController: controller)
present(navController, animated: true, completion: nil)
and then on the presented view controller if you use below code it will dismiss the view controller.
func dismissButtonPressed(){
self.dismiss(animated: true, completion: nil)
}
Cheers!!
Edit: My first answer addressed only part of the problem.
Looking further at your code...
It appears you are pushing HomeSearchViewController onto the navigationController stack, and then also presenting SearchRideViewController from HomeSearchViewController.
However...
In:
HomeSearchViewController viewDidLoad()
you create an instance of
SideBarViewController (leftViewController)
and you create an instance of
SlideMenuTrackerController (slideMenuController)
and assign
self as the .mainViewController and
leftViewController as the .leftMenuViewController
of slideMenuController.
If that's not confusing enough, you also:
AppDelegate.sharedInstance().window?.rootViewController = slideMenuController
which replaces HomeSearchViewController ... which you had just pushed onto the navigationController stack!
So, your view hierarchy is now (or, at least, seems to be if I am following your code):
Window
slideMenuController (instance of SlideMenuTrackerController)
+- searchViewController (instance of SearchRideViewController)
+- leftViewController (instance of SideBarViewController)
In order to "get back to" where you came from, you will need to re-create whatever VC you want to get to and (again) replace AppDelegate.sharedInstance().window?.rootViewController.
Without seeing your entire project, I'm not sure how you should really go about that.
[original answer]
In here:
func pushViewController() {
// ... the other lines
self.navigationController?.pushViewController(viewcontroller!, animated: false)
viewcontroller?.present(searchViewController!, animated: true, completion: nil)
}
You push viewcontroller and also .present(searchViewController!... from viewcontroller (that's a bit odd to begin with, but regardless)...
Then in here:
func navigateToPreviousController() {
self.dismiss(animated: true, completion: nil)
}
You .dismiss a view controller, but you never .pop back on the navigation controller's stack.
I have portrait only app with one screen in landscape only mode.
What I did:
I created a UINavigationController subclass and overridden the following:
import UIKit
class LandscapeVCNavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .landscape
}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return .landscapeLeft
}
}
Then using this navigationController to present my landscape viewcontroller like this:
if let vc = storyboard?.instantiateViewController(withIdentifier: StoryBoardIdentifiers.playerVCStoryboardIdentifier) as? PlayerViewController {
let navController = LandscapeVCNavigationController.init(rootViewController: vc)
present(navController, animated: true, completion: {
})
}
This works fine.
What I need:I need the landscape VC to be presented from the bottom(home button side) and should dismiss to the bottom(home button side). This is what happens currently.
You have to add a custom transition animation to change this default behaviour.
let transition = CATransition()
transition.duration = 0.3
transition.timingFunction = CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromLeft
self.view!.window!.layer.add(transition, forKey: nil)
self.present(navController, animated: false, completion:nil)
I am new to swift.I want to do animation while changing view from one view-controller to other view-controller.i am using prepareForSegue: method on button click, i have searched lot but did not find any solution do anyone have solution for this?
// call following code in the method where you want to add animation effect.
func buttonClicked(sender: UIButton){
let transition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromRight
self.navigationController?.view.layer.addAnimation(transition, forKey: nil)
self.navigationController?.pushViewController(vc!, animated: true)
}
// you can vary the duration of transition according to your convenience
// here transition.type are types of animation which you want to add on view. now we are pushing view so used push type. if want, you can google it for more types.
// subtype will decide the direction on animation.
You do not have to use prepareForSeque, you can do like this:
#IBAction func buttonClicked(sender: UIButton) {
let destinationVC = storyboard?.instantiateViewControllerWithIdentifier("viewcontrollerID") as! ViewControllerClass
self.presentViewController(destinationVC, animated: true, completion: nil)
}
viewcontrollerID is set in storyboard (it is called identity in attribute inspector (right panel)), it should be unique, ViewControllerClass is class of your ViewController
If you are using UINavigationController
#IBAction func buttonClicked(sender: UIButton) {
let destinationVC = storyboard?.instantiateViewControllerWithIdentifier("viewcontrollerID") as! ViewControllerClass
self.navigationController?.pushViewController(destinationVC, animated: true)
}