UINavigationController loses swipe back function when top bar is hidden - ios

I have a problem in that in swift when i set the UINavigationController to hidden using
navController.navigationBarHidden = true
it also stops the swipe back ability on any viewcontrollers that are pushed onto the stack. there doesn't seem to be any accepted fix, and i've tried setting the interactivePopGestureRecogniser as suggested by others, but this doesn't work any more either (i think that may have worked in swift 1?)
pls halp.

You can add your own interactive gesture and animation (called an interactive custom transition animation). It can be just like the default swipe gesture, or you can use use a different gesture and a different animation.

Related

UINavigationController push method load next VCs elements before animation completes

I have experienced a strange thing when I use UINavigationController with push method. Let's say we have a ViewController with two buttons (sign in & sign up). When user taps each of the buttons, the app presents the proper ViewController, but the UI elements, placed on that ViewController (for example UITextFields, Buttons) appearing first, while the transition animation still taking place.
I use a function to setup my layout in each ViewController and I'm not dealing with Storyboard.
I tried to use viewWillLayoutSubviews(), viewWillAppear(), etc, but experienced the same thing...
How can I reach smooth transition between the views?
Finally I solved it. The overlapping Viewcontroller did not have background color defined.

Change value for animation in animateTransition using UIPercentDrivenInteractiveTransition

I am trying to implement swipe up/down to dismiss view controller and everything is working great. If I start swiping up, it will finish the animation in the upwards direction and vice versa.
The problem appears when the user first swipes up but then decides to swipe the view controller down - how do I change the value in the animation to dismiss view controller to the bottom rather than to the top (set by the user's first swipe).
In my UIViewControllerAnimatedTransitioning controller I define the animation like this:
func animateTransition(transitionContext:UIViewControllerContextTransitioning) {
UIView.animateWithDuration(duration, animations: {
guard let transitionDelegate = self.transitionDelegate else {return}
snapshot.frame.origin.y = transitionDelegate.shouldAnimateUp ? -snapshot.frame.height : snapshot.frame.height
TransitionDelegate points to UIPercentDrivenInteractiveTransition controller (where the swipe gesture is defined). ShouldAnimateUp is defined in UIPanGestureRecognizer function like this:
shouldAnimateUp = translatedView.center.y < translatedView.frame.height / 2
That is if the view is in upper half, shouldAnimateUp = true and the other way around.
But unfortunately, when I call finishInteractiveTransition() func it uses the value which was initially set in UIView.animateWithDuration in UIViewControllerAnimatedTransitioning controller when dismissViewControllerAnimated(true, completion: nil) was called.
So, is there any way to change values for animation in UIViewControllerAnimatedTransitioning controller after dismissViewControllerAnimated(true, completion: nil) is called?
PS: I kind of struggled to define my problem in words (words are hard 🙄 ), so please tell me if you need additional info or if I should try to rewrite my explanation. Also, an additional hint: I would like the animation to work like image dismissal works in official Twitter app.
OK, I see what they're doing. It's actually more complicated that "if you swipe down and then up, it animates scene off upward". If you swipe down and back up, the Twitter app will cancel if you don't get much past where you started, but will go up if you pass where you started by some considerable portion (and are still swiping in that upward).
I must confess that I'm not crazy about this UX, because two very similar gestures can result in very different behavior. If you swipe down, keep your finger down, and then flick back upward, there is a seemingly arbitrary nature as to whether it's interpreted as a cancelation of the downward swipe or as an upward swipe. I personally think that if the user initiates a demonstrable downward gesture, that dragging back up should merely be a cancelation of the transition. But that's not the question here.
Anyway, if this is what you want to do, there are a couple of ways to achieve it:
You could consider using view property animator-based animations, which handle mid-flight changes to the animation more elegantly than older animation techniques. So, you theoretically could just addAnimations to your UIViewPropertyAnimator. But it seems messy to me.
See Advances in UIKit Animations and Transitions for more information about view property animators and how to use them with interruptible custom transitions.
When dismissing, you might not use UIViewControllerAnimatedTransitioning at all. Just animate the dismissal yourself.
For example, when you present, the UIPresentationController subclass can keep the presenting view (by returning false from should​Remove​Presenters​View). Then, when the gesture recognizer starts, it might not initiate a custom, interactive custom transition with dismiss at all, but instead merely adjust the frame of the presented scene (and modify the opacity of the dimming chrome). Then, at the end of the gesture, complete the animation manually and then the completion block can dismiss the presented view controller with no animation at all (because you've animated it yourself).
IMHO, this is architecturally inelegant. A view controller has no business mucking about with chrome that should be owned by the presentation controller. But, it works.
We should recognize that they might not have "presented" the full screen image at all. For example, they could have done simple view controller containment, but just added the child view controller scene to the existing scene. Then, the gesture could do whatever frame and dimming layer opacity changes it wanted, and when its done, just do the final animation and in the completion block, just remove the child view controller (e.g. willMove and removeFromParentViewController).
If I were to do this, I'd probably lean towards option 3, though I'd wager that it might not feel very satisfying for you, having invested time in custom interactive transitions already. Regardless, these are a couple of approaches you could consider.

UINavigationController animation from view controller with prompt

I am implementing an application that uses a UINavigationController. It currently shows 3 views, each a UITableViewController. The first view that is shown only has a title, while the other two have a title and prompt. All segues are created in the storyboard, which is rather straightforward:
The problem: As soon as I animate AWAY from a view that has a prompt, the animation glitches - the title (and sometimes the back button) "fly in" from the bottom, instead of from the right.
Example: https://youtu.be/N-K8piEJ1aY (recording with slow animations turned on)
Here you can see that the animation from first to second view works fine, but from second to third view is glitchy. animating back works.
This issue seems similar to Weird animations when changing NavigationItem prompt . The conclusion in that thread was that this only occurs on iOS 7, I am running on iOS 10.0/10.1, though. The issue occurs both in simulator and on the real device.
Any ideas?
The only solution I found was an absolute hack inspired by an absolute hack inspired by Catalina T. over on this post:
Either in viewWillAppear: on the appearing VC or after calling pushViewController:animated: on the navigation controller (or I'm guessing after calling performSegueWithIdentifier:sender: add the following code:
ObjC
// This is a hack that's because UINavigationBar with prompts is broken
navigationController.navigationBarHidden = YES;
navigationController.navigationBarHidden = NO;
Swift
// This is a hack that's because UINavigationBar with prompts is broken
navigationController.isNavigationBarHidden = true
navigationController.isNavigationBarHidden = false
where navigationController is a reference to the UINavigationController that's doing all the pushing (e.g. viewController.navigationController)
EDIT: It appears now there're other weird animations that occur when popping and repushing a VC, so this answer isn't a true solution. Leaving it up so as to help someone else down a similar rabbit hole.

View Controllers with transparent background overlapping when segueing (Swift)

I have multiple view controllers set up with push segues, they are all a grey colour with 50% opacity. The problem is when pushing to next VC they overlap and it doesn't look great at all.
I have been looking online and only answer I could find was to remove the animation. I do not want to do this as I have set up tap gesture swipes and the UI do not look that pleasing if there isn't the push animation!
Please see video example of it in action here -
http://tinypic.com/player.php?v=2ez6x7a%3E&s=9#.Vnh6SJOLSX0
Solution I:
If you are ok to remove the animation, Set animated false on UINavigationController.pushViewController in Swift
self.navigationController!.pushViewController(viewController, animated: false)
Solution II:
If you don't, then you may need to hide the current ViewController before you push the new viewcontroller as follows:
yourCurrentViewController.view.hidden = YES;

UIView being cached?

Ok this is a little hard to explain but here I go. On "View1" I use a UIView animation to go to "View2". The animation I do is a fade through black, switching views. I get to View2 by doing -addSubview. Now lets say we are on View2, and my action gets called to go to View3 using presentModalView. Since I need to remove the "View2" view, I do [self.view removeFromSuperview]; in my viewDidDisappear method so that the animation going to View3 is not screwed up.
Here is the problem, when I go from my "View3" back to "View1" I use a presentModalView again with an animation flip. Now you know when you usually flip views, you see a background in the back of a color (usually white), instead it is my "View2". So it is like it is being cached in a way.
Does anyone know why this is? If I need to post code, I can.
You can actually check this tutorial about using the UINavigationController:
http://www.icodeblog.com/2008/08/03/iphone-programming-tutorial-transitioning-between-views/
To hide your Navigation Bar you can actually see this post:
Is it possible use UINavigationController but hide its navigation bar (replace it with customized toolbar) and go back button
Edit 1:
Uploaded the project now here: http://www.2shared.com/file/qU-QT8fl/Project.html
Read the ReadMe.text file. :P

Resources