View Controller Transitions

Source: Internet
Author: User
Tags image filter

Custom transition Animations

One of the most exciting features of IOS 7 is the provision of new APIs to support custom transition animations between view Contrioller. Before IOS 7 was released, I wrote some transitions between view controllers myself, which is a tricky process, and it's not completely supported by Apple, especially if you want to make this transition animation interactive.

Before I go on reading, I need to make a statement: This API is recently released and there is no known best practice yet. In general, developers need to explore a few months to come up with best practices for new APIs. So consider this article as an exploration of a new API, not a best practice introduction to this new API. If you have a better practice with this API, please do not hesitate to enlighten us, we will update your practice to this article.

In the beginning of the study of the new API, let's look at the default behavior between navigation controllers in IOS 7 that has changed: In navigation Controller, the animation that switches two view controllers becomes more Be interactive. For example, if you want pop a view controller to go out, you can drag your finger from the left edge of the screen and slowly drag the current view controller right out of the screen.

Next, let's take a look at this new API. A very interesting phenomenon is that this part of the API uses a lot of protocols rather than specific objects. It looked a little strange at first, but I personally prefer the API design because it gives us developers more flexibility. Let's do a simple thing: in Navigation Controller, implement a custom push animation effect (the sample code in this article is hosted on Github). In order to accomplish this task, you need to implement UINavigationControllerDelegate the new method:

Editor's note   The author of the original text in the sample code above Github and the code in the article have some discrepancies (for example, here is Push, But in the sample code is POP). If you want, you can also refer to this revised version of the sample code, and the article's code difference is smaller.

 -(id<uiviewcontrolleranimatedtransitioning        >) Navigationcontroller: (uinavigationcontroller *) Navigationcontroller Animationcontrollerforoperation: (uinavigationcontrolleroperation) Operation Fromviewcontroller: (uiviewcontroller*) Fromvc Toviewcontroller: (UIV iewcontroller*) tovc{if (Operation = = Uinavigationcontrolleroperationpush) {return self.animator;} return nil;}        

As you can see from the code above, we can return different animator based on different operation (Push or POP). We can save animator in a property to share between multiple operation, or we can create a new animator object for each operation, and there's a lot of flexibility here.

In order for the animation to run, we create a custom class and implement UIViewControllerContextTransitioning this protocol:

@interface Animator : NSObject <UIViewControllerAnimatedTransitioning>@end

This protocol requires that we implement two methods, one of which defines the duration of the animation:

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext{    return 0.25;}

Another method describes the performance of the entire animation:

- (void) Animatetransition: (id<uiviewcontrollercontexttransitioning>) transitioncontext{uiviewcontroller* Toviewcontroller = [Transitioncontext viewcontrollerforkey: Uitransitioncontexttoviewcontrollerkey];uiviewcontroller* Fromviewcontroller = [Transitioncontext viewcontrollerforkey:    Uitransitioncontextfromviewcontrollerkey]; [[Transitioncontext Containerview] Addsubview:toviewcontroller.view]; Toviewcontroller.view.alpha =  0; [uiview animatewithduration:[self transitionDuration: Transitioncontext] animations:^{fromviewcontroller.view . Transform = Cgaffinetransformmakescale (0.1, 0.1); Toviewcontroller.view.alpha =  1; } completion:^ (bool finished) {Fromviewcontroller.view< Span class= "hljs-variable" >.transform = cgaffinetransformidentity; [Transitioncontext completetransition:! [Transitioncontext transitionwascancelled]]; }];}

From the example above, you can see how to apply the protocol: This method obtains the transition context by accepting a type id<UIViewControllerContextTransitioning> parameter. It is worth noting that after performing the animation, we need to call Transitioncontext's completeTransition: method to update the view controller's state. The rest of the code is the same as before IOS 7, we get two view controllers that need to be transitions from the transition context, and then use the simplest UIView animation to achieve the transition animations. That's all the code, and we've implemented a transition animation of the zoom effect.

Note that this is just a transition animation that implements the custom effect for the Push operation, that the default sliding effect is used for POP operations, and that the transition animations we implemented above do not interact, so let's take a look at solving the problem.

Interactive transition Animations

To be able to animate the interaction is very simple, we just need to overwrite UINavigationControllerDelegate the other method:

- (id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController*)navigationController                          interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>)animationController{    return self.interactionController;}

Notice that in the noninteractive animation effect, the method returns nil.

The interaction controller returned here is UIPercentDrivenInteractionTransition an instance of the class, and the developer does not need any configuration to work. We created a drag gesture (Pan recognizer), and here's the code to handle the gesture:

if (panGestureRecognizer.state == UIGestureRecognizerStateBegan) {    if (location.x >  CGRectGetMidX(view.bounds)) {        navigationControllerDelegate.interactionController = [[UIPercentDrivenInteractiveTransition alloc] init]; [self performSegueWithIdentifier:PushSegueIdentifier sender:self]; }} 

Editor's note the code here has a hint of meaning, and the actual code is somewhat out of the way, in order to respect the original author, we did not make changes, you can refer to the original text on Github sample code for comparison, you can also refer to the revised version of the sample code.

The next animation effect is set to interactive (by setting this property) only when the user starts to touch from the right half of the screen, interactionController and then executes the method performSegueWithIdentifier: (if you are not using the storyboards, call pushViewController... such methods directly). In order for the transition animation to continue, we need to call a method of the interaction controller:

else if (panGestureRecognizer.state == UIGestureRecognizerStateChanged) {    CGFloat d = (translation.x / CGRectGetWidth(view.bounds)) * -1; [interactionController updateInteractiveTransition:d];} 

This method calculates a percentage based on the distance dragged by the user's finger, and the animated effect of the toggle goes along with that percentage. The coolest thing is that the interaction controller works with the animation controller, and we only use the simple UIView animation animations, but the interaction controller It controls the progress of the animation, and we don't need to associate the interaction controller with the animation controller because all of these systems are automatically done for us in a decoupled way.

Finally, we need to determine whether the operation ends or is canceled based on the stop state of the user gesture, and calls the corresponding method in the interaction controller:

else if (panGestureRecognizer.state == UIGestureRecognizerStateEnded) {    if ([panGestureRecognizer velocityInView:view].x < 0) { [interactionController finishInteractiveTransition]; } else { [interactionController cancelInteractiveTransition]; } navigationControllerDelegate.interactionController = nil;}

Note that when the switch is complete or canceled, remember to set the interaction controller to nil. Because if the next transition is non-interactive, we should not return this old interaction controller.

Now we've implemented a fully customizable, interactive transition animation. With a simple gesture recognition and a class provided by UIKit, a few lines of code are done. For most applications, you will be able to read here and use the method mentioned above to achieve the desired animation. But if you want to make more depth customizations to transitions or interactive effects, continue to the next section.

customizing animations with Gpuimage

Let's take a look at how to really, completely customize the animation effect. This time we do not use UIView animation, even the Core animation do not need to completely own to achieve all the animation effect. In the Letterpress-style project, I initially tried to animate with the Core Image, but on my IPhone 4, the animation was rendered up to 9 frames per second, far from the 60 frames/second I wanted.

But when I use Gpuimage, it's incredibly easy to achieve a very nice animation. Here we want to achieve the transition effect is: Two view controller pixelated, and then melted together. This is done by intercepting the two view controllers first, and then using the Gpuimage image filter (filter) to process the two.

First, let's start by creating a custom class that implements the UIViewControllerAnimatedTransitioning UIViewControllerInteractiveTransitioning two protocols:

@interface GPUImageAnimator : NSObject  <UIViewControllerAnimatedTransitioning,   UIViewControllerInteractiveTransitioning>@property (nonatomic) BOOL interactive;@property (nonatomic) CGFloat progress;- (void)finishInteractiveTransition;- (void)cancelInteractiveTransition;@end

To speed up the animation, we can load the picture into the GPU at once, and then all the processing and drawing is performed directly on the GPU, and it does not need to be transferred to CPU processing (this data transfer is very slow). By using Gpuimageview, we can use OpenGL drawing directly (we don't need to write the underlying code of OpenGL, as long as we continue to use the Gpuimage encapsulated interface).

Creating a filter chain (filter chain) is also very intuitive, and we can setup see how to construct it directly in the method of the sample code. The challenge is to get the filter to "move" too. Gpuimage does not directly provide us with animated effects, so we need to update the filter to achieve a dynamic filter effect every render frame. CADisplayLinkThis work can be done using:

This chapter is missing from the sample code in the original editor's note, and I found the relevant source code on the original author's GitHub Gist and put it on GitHub, where you can find it.

self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(frame:)];[self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];

In the frame method, we can update the animation progress based on time and update the filter accordingly:

- (void) Frame: (cadisplaylink*) link{Self. Progress = MAX (0, MIN (link. Timestamp-Self.starttime)/Duration, 1)); self.blend.mix = self.progress; self.sourcepixellatefilterself.progress *0.1; self.targetpixellatefilter1-self .progress) *0.1; [self Triggerrenderofnextframe];}         

Well, basically it's done. If you want to achieve interactive transitions, you can't use time here, but instead update the animation progress based on gestures, the rest of the code is basically the same.

This is a very powerful feature, you can use any existing filters in Gpuimage, or write your own OpenGL shader (shader) to achieve the desired effect.

Conclusion

This article only explores transition animations between the two view controllers in the navigation controller, but these practices are also common in the tab controller or any of the view controller containers that you define yourself. In addition, in IOS 7, UICollectionViewController also extended, you can now automatically and interactively between the layout of the animation switch, the same mechanism behind the use of the same. It's so powerful.

When discussing the API with Orta, he mentions that he has been using these mechanisms extensively to create lighter-weight view controllers. Instead of maintaining states in a view controller, create a new view controller, use a custom transition animation, and then move your various view in this transition animation.

View Controller Transitions

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.