Nav. Controller Preventing Segue Transition From Animating - swift

Background:
My storyboard flow: [Nav VC] -> [VC1] -> [Home VC] -> [Settings VC] -> ...
I am currently using the Hero transition animation library to achieve a pull down effect (from top to bottom) when segueing from my Home VC to the Settings VC. In the storyboard have made sure to have hero enabled on my Nav, as well as the Home and Settings VC. As for the actual segue code this is what I have in the Home VC:
//in Home View Controller
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "goToEditScreen") {
let editVC = segue.destination as! ProfileMenuViewController
//set the animation style
editVC.hero.modalAnimationType = .selectBy(presenting: .slide(direction: .down), dismissing: .slide(direction: .up))
editVC.documentID = self.documentID
}
}
The Issue:
The custom animation does not seem to be triggering, instead defaulting to the basic left to right segue. However, in the storyboard if deselect Navigation VC as the 'Initial View Controller', and instead change it to the 'VC1', then the Hero animation works (with the caveat that the Nav Bar is gone from the app).
What I Have Tried:
Like mentioned above I have tried switching the initial VC to not be the Nav VC and it seemed to work except I lose the nav bar. I also tried adding the same Hero code to the Settings VC in viewDidLoad()
hero.modalAnimationType = .selectBy(presenting: .slide(direction: .down), dismissing: .slide(direction: .up))
but to no avail, so I removed it.
If anyone has any insight into why this might be happening, please let me know!

Related

Performing segue with UINavigationController (without IBAction)

It's easier to show you a drawing and then explain.
Dashboard Storyboard
I have 2 separate UIViewControllers (i've included just one in the drawing, the other is irrelevant) embedded in container view called ContainerViewController.
Post Storyboard
NewPostViewController shows a UIButton that presents TextPostViewController. As you can see, all of them are embedded in UINavigationControllers. Now, once the completion block of the new post is being called, I have to present the ContainerViewController and it needs to handle it's own logic. The problem is that it's embedded in UINavigationController and once I present it, the UITaBbar is hidden.
I tried to do this:
self.performSegue(withIdentifier: "TextPostToNavContainerVC", sender: nil)
The transition is successful but I'm losing the UITabBar, even though in the DashboardViewController and the ContainerViewController I called:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tabBarController?.tabBar.isHidden = false
}
What am I doing wrong or is there are better way to do that?
You should instantiate the tab bar controller. not the view controller.
Imagine you're putting a initial view controller ahead of your tab bar controller. Making your tab bar not being pushed
If I undestand it correctly.
You are doing this
Segue connect to a view controller
But you should actually do this Segue connected to a tab bar controller
You can try to add it as a child to control it's frame like this
let textPost = self.storyboard?.instantiateViewController(withIdentifier: "containerID") as! TextPostToNavContainerVC
textPost.view.frame = CGRect(x:20,y:0,width:self.view.frame.width,height:self.view.frame.height-50)
self.view.addSubview(nvc.view)
self.addChildViewController(textPost)
textPost.didMove(toParentViewController: self)

UITransitionContextFromViewControllerKey is returning nil

So, I am using the Elastic Transition pod (Cocoapods), and when I transition my app crashes because the UITransitionContextFromViewControllerKey key is nil. I am really confused as to why that value would be nil. What are some probable causes and solutions to resolving this error?
So here is some of my code for when I am transitioning into the next view controller:
func handleTap(sender: AnyObject) {
transition.sticky = true
transition.transformType = .TranslateMid
transition.showShadow = true
transition.edge = .Left
transition.startingPoint = sender.center
performSegueWithIdentifier("mySegue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
segue.destinationViewController.transitioningDelegate = transition
segue.destinationViewController.modalPresentationStyle = .Custom
}
Then, when it is trying to transition my app crashes complaining that this line of code (in Elastic Transition) is returning nil:
transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
According to the ElasticTransition Github page, if a view controller is presented modally with elastic transition, then the destination view controller's transitioningDelegate needs to be set to ElasticTransition and modalPresentationStyle to .Custom. However, if the view controller is pushed onto a navigation controller stack using the elastic transition, then only the navigationController?.delegate needs to be set to ElasticTransition.
After some chatting, #Harish told me that he uses a push segue. However, the code in prepareForSegue is the setup code for when one presents a view controller modally. That is likely the reason why UITransitionContextFromViewControllerKey returns nil. So I believe the solution is to set the navigationController's delegate to ElasticTransition somewhere, and remove the code in prepareForSegue.

how hide tap bar on another controller before show everything else

I have a simple tap bar example. And for my next view i have a ViewController with tableView and on bottom textInput. when i want hide tap bar i have a code:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject? {
if segue.identifier == "showMe" {
(segue.destinationViewController as! MyViewController)
destinationController.hidesBottomBarWhenPushed = true
}
}
and on my next view when i tap a row on tableView i see first rendering tap bar and then tap bar is hidden and on last input Edit goes down :( how hide this tap bar before show next screen ?
This isn't exactly the best solution, but its a workaround:
set destinationController.hidesBottomBarWhenPushed = false
set contraints properly in your view controller (as if there is no tab bar)
use the following code (as shown) in the view controller where you want to hide the tab bar:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.tabBarController?.tabBar.frame = CGRectZero
self.tabBarController?.tabBar.userInteractionEnabled = false
}
This will make sure that the tab bar is hidden. Now the Autolayout constraints will make sure your view displays correctly with the tab bar height as zero.

unwind segue result different with master and detail views

i'm fairly new to swift and having some difficulty with unwind segues in a master detail application.
the unwind seems to work fine dismissing my popovers on the iPhone, however when i try the same thing on the iPad, the popover remains.
If i add a dismissViewControllerAnimated to the presenting viewController's unwind handling action, then the iPad version works fine and dismisses the popover, however the iPhone version dismisses the popover and then dismisses the view that presented the popover. i.e. dismisses two views.
I have worked out that the problem is that popover's are automatically dismissed with an unwind when presented modally such as on an iPhone. However when presented as true popovers they don't dismiss with an unwind segue. Could somebody help me figure out how to manage both cases so that only the popover will be dismissed. Thank you very much in advance.
Okay. after a long time working on this i managed to come up with a solution. i used a popoverpresentationcontroller and declared the presenting controller as the delegate. by then adding an additional function forcing the iPhone to use the popover in lieu of the modal presentation, the presentation and dismissal is consistent for the iPhone and iPad. the code is below. I just used a generic UIViewController in the if let vc statement so that I could use this with a popover that's imbedded in a navigation controller also.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let identifier = segue.identifier {
switch identifier {
case "My Segue Identifier" :
if let vc = segue.destinationViewController as? UIViewController {
if let ppc = vc.popoverPresentationController {
ppc.delegate = self
}
}
default: break
}
}
}
additionally you need to add the following function to prevent the modal presentation on the iPhone:
func adaptivePresentationStyleForPresentationController (controller:UIPresentationController)-> UIModalPresentationStyle {
return UIModalPresentationStyle.None
}

What is the correct way to push a View Controller after a selection from a menu?

In my app I have a "home" screen from which I can present a hamburger menu (coded as a modal transition in Storyboard).
The menu is a UITableView where a user will select a row. The menu has a delegate method which calls the following function in the presenting screen (my "home" screen)
// Menu delegate method
func menuDidExit(menuVC:MenuVC) {
self.dismissViewControllerAnimated(true, completion: {
// After dismissal of menu, call the chosen option
if let selectedOption = menuVC.menuSelection {
self.performSegueWithIdentifier(menuVC.menuSelection?.rawValue, sender: self)
}
})
}
This function will both dismiss the menu view controller, and then (once that transition is complete), present a second view controller based upon the chosen menu option, using the "performSegueWithIdentifier" command.
The issue that I have is that while the menu dismiss works fine (the menu slides off screen gracefully) - there is no animation for the presentation of the next view controller - it simply appears on screen after the menu has been dismissed.
I can call the desired view controller via a button/segue, and all works well, however when it is part of the completion block above it fails to animate the transition. This leads me to believe that there is something fundamentally wrong with my approach - hence the question, what is the correct way to push a second view controller after handling the dismissal of the first.
Many thanks for any suggestions
I think you can use this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
self.dismiss(animated: true) {
//dismiss your menu here
}
}
Hope it can help you.
Please let me know if it not work.
Thanks