When presenting a UIViewController that implements UIViewControllerTransitioningDelegate it is easily possible to customize the viewtransition.
Now I would like to know if I can customize a viewtransition for a subview? Lets say I have a tapable tile that currently flips when tapped (UIViewAnimationOptionTransitionFlipFromRight). Although that is a very nice effect I rather would like to customize this transition. But I do not know how to start..
To clarify I would like to use an AnimationController<UIViewControllerAnimatedTransitioning> to handle my subviewtransition - is that possible?
Any suggestions?
Well this is not possible out of the box but there are some ways to achieve that but this will need some deeper knowledge of how the custom transition are working in detail.
Here are two articles describing what you are looking for in detail:
Custom Container View Controller Transitions
http://www.objc.io/issue-12/custom-container-view-controller-transitions.html
Interactive Custom Container View Controller Transitions
http://www.iosnomad.com/blog/2014/5/12/interactive-custom-container-view-controller-transitions
Answering with regards to your comment : you cannot.
From UIViewControllerAnimatedTransitioning protocol documentation :
Adopt the UIViewControllerAnimatedTransitioning protocol in objects that implement the animations for a custom view controller transition. The methods in this protocol let you define an animator object, which creates the animations for transitioning a view controller on or off screen in a fixed amount of time.
This protocol is only for UIViewControllers (and its descendants), and UIView doesn't inherit from it.
Related
I have a UIView which I am using as a seperate module and can include it anywhere I want to. Now I want to navigate to a UIViewController on click of the button inside the UIView.
Hope this is pretty clear.
Short answer: You shouldn't. You need to read up on the MVC design pattern. A UIView is a view object. You are trying to add controller behavior to a view object.
You should take a look at parent/child view controllers, container views, and embed segues. You could easily create a view controller that manages a "tile" inside another view controller, and sends messages to it's parent when the user taps buttons. This is a very common way of doing things.
The best way to do this is to supply the ViewController to the view as a delegate, conforming to a protocol you create for it.
For instance, if you UIView is used to pick an image, then the delegate should have a method akin to:
(void)view:(UIView*)view choseImage:(UIImage*)image;
I am attempting to create a custom view controller container, which will display a drawer at the bottom of the screen, like the Apple mail or music apps, and I want the user to either be able to tap on it to transition it to fullscreen, or slide it up interactively to reveal the content.
I have the drawer working, using a UIPanGestureRecognizer to slide it.
I can implement this by adding the content controller as a child controller, the content view to the hierarchy and call viewWillAppear: and viewDidAppear: when appropriate.
But I wish to allow the content view controller to animate alongside the swipe (e.g. any animations in viewWillAppear:, like with interactive pop), thus I am looking at custom modal presentation and UIPercentDrivenInteractiveTransition, but I am hitting a wall, and I can't see why this is happening. I have setup a transitioning delegate, returning a custom animation controllers and an interaction controller which is a UIPercentDrivenInteractiveTransition object.
My drawer is part of the container controller's view hierarchy, and naturally I want the content controller's view to be a subview of the drawer. But when calling presentViewController:animated:completion:, a new UITransitionViewsubview is added to the UIWindow, supposedly for where the transition animation should occur. But this kills my UIPanGestureRecognizer and the user cannot perform the swipe to open the drawer.
I tried creating a custom UIPresentationController and other ways to control where in the hierarchy this containerView should be, but I am unable to change the behavior.
Is what I am attempting to do the correct way? What have I missed?
If anyone is interested, here is my framework: LNPopupController
Update 2015.11.19
A demo project as well
Obj-C -> https://github.com/saiday/DraggableViewControllerDemo
Swift 2.x -> https://github.com/ostatnicky/DraggableViewController
Swift 4.x -> https://github.com/satishVekariya/DraggableViewController
Thanks #avdyushin mentioned my blog post.
And yes, my post Draggable view controller? Interactive view controller! is a tutorial just about your topic.
Quoted from my blog post:
How to do it
Design philosophy
There is no two UIViewController in together, instead there's only one UIViewController at a time. When user begin drag on certain subview, present another view controller with custom UIViewControllerAnimatedTransitioning by custom UIPercentDrivenInteractiveTransition protocol.
Technical things
These two protocols is the foundation of customize interactive UIViewController transitions. In case you don't know yet, take a glance before starting.
1. UIViewControllerAnimatedTransitioning protocol
2. UIPercentDrivenInteractiveTransition protocol
An updated answer for iOS 10: this is now trivial using UIViewPropertyAnimator.
UIViewPropertyAnimator is a continuation of the block-based animation concept, taken to its logical continuation - an object oriented wrapper around animations. This allows for much more control, such as controlling the completion of the animation using fractionComplete - precisely what was needed here.
While searching how to perform custom animations when transitioning from one controller to another I found some info about UIViewControllerAnimatedTransitioning.
So the question is: why do we even need this if we have custom segues? Are they interchangeable or not? If yes, why does Apple provide two ways of doing the same task?
Some differences:
Segues can only be used with storyboards.
Animator objects can be used programmatically, or along with segues.
Animator objects allow you to set a customized final position and size for your new view controller.
Animator objects can be configured to do special animations with navigation controllers and collection views.
Animator objects also allow interactive transitions using UIViewControllerInteractiveTransitioning, which segues don't.
I want to handle transitions between two instances of the same view controller class, using pan gestures.
I've read almost every transitions can be handled by segues, but is it the same when using pan gestures?
Segues don't seem to be a good fit for this kind of transitions.
For the moment, I have a master view controller which instantiates to sub view controllers. The gesture related code resides in the master view controller.
It works well, but I believe there has to be a solution where all the controller management stuff is done in the storyboard.
What is the best place in my code to handle this kind of transitions?
It sounds to me like what you want is a UIPageViewController set up to scroll instead of page curl (That's a settable property) A page view controller would do all the work for you.
There is a sample app in the Xcode docs called PhotoScroller that shows how to set this up. It does lots of other stuff too, (pinch to zoom and image tiling) but you can ignore that.
If you can't get a UIPageViewController to give you the transition you want then you might need to build your own custom parent view controller class. Embedding a single child using a container VC and an embed segue is trivial. I haven't tried to embed multiple children in the same container yet. using embed segues yet. I've done transitions between child VCs using the "manual" parent/child VC calls that were added in iOS 5
I've found a really great article on the way to implement custom transitions with iOS 7, whether they're interactive or not: http://www.captechconsulting.com/blog/tyler-tillage/ios-7-tutorial-series-custom-navigation-transitions-more
It comes with a very detailed demo.
Animations should be classes implementing the UIViewControllerAnimatedTransitioning or UIViewControllerInteractiveTransitioning protocols.
The code using the gesture recognizer can reside in those classes.
The animation can then be returned in the following methods of your navigation controller delegate:
navigationController:animationControllerForOperation:fromViewController:toViewController:
navigationController:interactionControllerForAnimationController:
This way I can plug the animation to whatever controller I want to.
I hope it could help someone.
I implemented my own custom container view controller and I try to make it compatible with iOS 7 view controller transitions. I make my custom container view controller conform to UIViewControllerContextTransitioning and I send self when I call transitionDuration: and animateTransition:. It all works fine as long as I use only animated transitions.
Now I want to make it work with interactive transitions, so I call the interaction controller's startInteractiveTransition: instead of the animation controller's animateTransition:, using self again as a parameter. However, if I use a UIPercentDrivenInteractiveTransition as the interaction controller, it then calls a _animator method on my context (which is the container view controller itself). Of course, I haven't implemented this method which is private and undocumented, so it crashes...
Am I missing something in my implementation? Is UIPercentDrivenInteractiveTransition only compatible with Apple classes because it uses some implementation magic (as when it requires that everything should be in a UIView animation block)? The documentation and header files make it look like we can implement our own container view controllers and still use custom transitions, but is it really true or just wishful thinking because nobody would actually do that?
If I can't use UIPercentDrivenInteractiveTransition, then where exactly should the interaction/animation logic be? In the UIViewControllerTransitionCoordinatorContext object? In the UIViewControllerInteractiveTransitioning object (most likely, this object is the driver...)? Or in the UIViewControllerAnimatedTransitioning object (this is probably where the real animation should happen, but would that mean calling animateTransition: several times during the interaction? Or adding new methods for each step of the interactive transition?)
Edit: The documentation says:
A percent-driven interactive transition object drives the custom animation between the disappearance of one view controller and the appearance of another. It relies on a transition animator delegate—a custom object that adopts the UIViewControllerAnimatorTransitioning protocol—to set up and perform the animations.
There is no UIViewControllerAnimatorTransitioning protocol. Assuming it is a mistake, or a name change that happened during iOS 7 development and it is actually the UIViewControllerAnimatedTransitioning protocol, how do we link the interaction controller with the animation controller? I guess it's the responsibility of the view controller driving the transition but I don't see any API to make this link, so it would mean that UIPercentDrivenInteractiveTransition is indeed reserved for Apple classes?
I'm trying to do the same on my own and ended up writing my own UIPercentDrivenInteractiveTransition equivalent. Seems like the percent driven transition asks for the animation and actually starts it after the interactive transition is started. I've got some trouble with implementing the reverse animation when canceling though.