IOS hands-on animation of custom transitions _ios

Source: Internet
Author: User
Tags comments uikit

Transitions animation This thing, say simple also simple, can pass presentViewController:animated:completion: and dismissviewcontrolleranimated:completion: This set of functions shows up in a modal view and hides the view. If you use the Navigationcontroller, you can also call pushviewcontroller:animated: and Popviewcontroller This set of functions to press the new view controller stack and stack.

All transition animations in the following illustration are custom animations that can be difficult or impossible to achieve without custom animations:

Because of the video screen, some effects can not be fully displayed, such as it actually supports the horizontal screen.

The effect of customizing a transition animation is complex, and it is possible to create hidden bugs if you simply copy a code that works and you don't understand the principle. This article introduces the following several knowledge:

1. Traditional implementation methods based on closures and their drawbacks
2, custom present transitions animation
3. Interactive (Interactive) Transitions animation
4. Transition Coordinator and Uimodalpresentationcustom
5, Uinavigationcontroller Transitions animation

Before starting a formal tutorial, you first need to download the demo, the text is pale in front of the code, the demo contains enough comments to explain this article all the points of knowledge. Second, you need to know a few of these background knowledge.

From and to
In code and text, Fromview and Toview are often present. If the wrong understanding of their meaning causes the animation logic to be completely wrong. Fromview represents the current view, Toview represents the view to jump to. If it is present from a view controller to B, then A is from,b to. From the B View controller dismiss to A, B becomes from,a. In a picture:

Presented and Presengting
This is also a set of relative concepts that are easily confused with Fromview and Toview. In simple terms, it is not affected by present or dismiss, and if it is present from a view controller to B, then a always presentedviewcontroller,b always presentingviewcontroller.

Modalpresentationstyle
This is an enumeration type that represents the type of animation when present. There are only two kinds of custom animation effects: Fullscreen and custom, the difference is that fullscreen will remove the Fromview, and custom will not. For example, in the GIF at the beginning of the article, the third animation effect is custom.

Block-based animation
The simplest animation for transitions is to use the Transitionfromviewcontroller method:

Although this method is outdated, its analysis helps to understand the knowledge behind it. It has a total of 6 parameters, the first two indicate from which VC start, jump to which VC, the middle of two parameters to indicate the timing of the animation and options. The last two parameters represent the specific implementation details of the animation and the callback closure.

These six parameters are in fact the six elements necessary for a transition animation. They can be divided into two groups, the first two parameters of a group, representing the page's jump relationship, followed by a group of four, representing the animation's execution logic.

One of the drawbacks of this approach is that the customization is not high (you'll find that you can customize more than just animation), another disadvantage is that the reusability is not good, it can be said that the degree of coupling is relatively large.

Of the last two closures, it is expected that Fromviewcontroller and Toviewcontroller parameters will be used, and that they are the key to animation. Assuming that view controller A can jump to B, C, D, E, F, and that the jump animation is basically similar, you will find that the Transitionfromviewcontroller method is copied multiple times, and only a small amount of content is modified at a time.

Custom present Transitions Animation
for the sake of decoupling and increasing the degree of customization, we learn the correct use posture of transition animations.

The first thing to understand is a key concept: The Transition animation agent, which is an object that implements the Uiviewcontrollertransitioningdelegate protocol. We need to implement this object ourselves by providing one or more of the following objects for Uikit:

1, animator:

It is the object that implements the Uiviewcontrolleranimatedtransitioning protocol, for controlling the duration of animation and animation display logic, the agent can provide animator for present and dismiss process respectively, can also provide the same animator.

Interactive animator: Similar to animator, but it is interactive and will be described in detail later

Presentation Controller:

It can be more thorough customization of the present process, such as modifying the size of the displayed view, adding a custom view, and so on, which will be described in detail later.

In this section, we first introduce the simplest animator. Review the 6 elements that are necessary to transition animations, which are divided into two groups and are not related to each other. The function of animator is equal to the four elements of the second group, that is to say, for the same animator, it can be applied to a jump B or a jump C. It represents the animation logic of a common page jump and is not limited to specific view controllers.

If you read this passage, the entire custom transition animation logic is clear, with view Controller a jumping to B for example:

    • Create an animation agent, when things are simpler, a can act as an agent
    • Set the transitioningdelegate for B to the proxy object created in step 1
    • Call PresentViewController:animated:completion: and set the parameter animated to True
    • The system will find the animator provided in the agent, which is responsible for animation logic by animator

In a concrete example, the explanation is:

/This class is equivalent to a class Crossdissolvefirstviewcontroller:uiviewcontroller, 

  Uiviewcontrollertransitioningdelegate {//This object is equivalent to b crossdissolvesecondviewcontroller.transitioningdelegate = self 
             Click on the button-triggered function func animationbuttondidclicked () {Self.presentviewcontroller (Crossdissolvesecondviewcontroller, Animated:true, Completion:nil)}//The following two functions are defined in the Uiviewcontrollertransitioningdelegate Protocol//for present and DIS Miss offers animator Func Animationcontrollerforpresentedcontroller (Presented:uiviewcontroller, PresentingController Presenting:uiviewcontroller, Sourcecontroller source:uiviewcontroller)-> uiviewcontrolleranimatedtransitioning ?

  {//can also use Crossdissolveanimator, the animation effect has different//return Crossdissolveanimator () return Halfwayspringanimator ()} Func Animationcontrollerfordismissedcontroller (Dismissed:uiviewcontroller)-> Uiviewcontrolleranimatedtransitioning?

{return Crossdissolveanimator ()}} 

The key to animation is how animator is implemented, it implements the Uiviewcontrolleranimatedtransitioning protocol, at least two methods need to be implemented, and I recommend that you read the comments in the Animatetransition method carefully. It is the core of the entire animation logic:

Class Halfwayspringanimator:nsobject, uiviewcontrolleranimatedtransitioning {///Sets the duration of the animation func transitionduration ( Transitioncontext:uiviewcontrollercontexttransitioning?) -> Nstimeinterval {return 2}///set the animation to the way, with detailed comments, this method elsewhere in the demo no longer explains Func Animatetransition (Transitioncont ext:uiviewcontrollercontexttransitioning) {Let Fromviewcontroller = Transitioncontext.viewcontrollerforkey ( Uitransitioncontextfromviewcontrollerkey) Let Toviewcontroller = Transitioncontext.viewcontrollerforkey ( Uitransitioncontexttoviewcontrollerkey) Let Containerview = Transitioncontext.containerview ()//need to pay attention to from/to and PR
    esented/presenting Relationship//For a presentation://Fromview = the presenting view.
    Toview = the presented view.
    For a dismissal://Fromview = the presented view.

    Toview = the presenting view. var Fromview = Fromviewcontroller? View var Toview = Toviewcontroller?. View//IOS8 introduces the Viewforkey method, using this method as much as possibleInstead of directly accessing the Controller view property//For example, in form sheet style, we add shadows or other decoration to Presentedviewcontroller view, Animator the entire decoration view//animation effect, while Presentedviewcontroller view is only a child of decoration view if Transitioncontext. Respondstoselector (Selector ("Viewforkey:")) {Fromview = Transitioncontext.viewforkey ( Uitransitioncontextfromviewkey) Toview = Transitioncontext.viewforkey (Uitransitioncontexttoviewkey)}//We Let the Toview origin.y in half of the screen so that it bounces off the middle of the screen instead of bouncing off the bottom of the screen and gradually becomes opaque toview. frame = CGRectMake (fromview!. Frame.origin.x, fromview!. FRAME.MAXY/2, fromview!. Frame.width, fromview!. Frame.height) Toview? Alpha = 0.0//When present and dismiss, the Toview must be added to the view hierarchy Containerview?.

    Addsubview (toview!) Let transitionduration = Self.transitionduration (transitioncontext)//Using spring animation, has a spring-loaded effect, Make sure to call the Completetransition method after the animation uiview.animatewithduration (Transitionduration, delay:0, usingspringwithdamping:0.6 , initialspringvelocity:0, Options:. Curvelinear,Animations: {()-> Void in toview!. Alpha = 1.0//gradually becomes opaque toview?  frame = Transitioncontext.finalframeforviewcontroller (toviewcontroller!) 
        Move to the specified location}) {(Finished:bool)-> Void in Let wascancelled = transitioncontext.transitionwascancelled ()

 Transitioncontext.completetransition (!wascancelled)}}}

The core of the animatetransition approach is to get the necessary information from the Transitions animation context to complete the animation. A context is an object that implements the Uiviewcontrollercontexttransitioning, and its role is to provide the necessary information for the Animatetransition method. Instead of caching any information about animations, you should always get them from the context of the transition animation (such as Fromview and Toview) to ensure that you always get the latest and correct information.

After getting enough information, we call the Uiview.animatewithduration method to hand the animation to the core animation processing. Never forget to execute the Completetransition method after the end of the animation call.

The knowledge in this section has detailed code in the cross dissolve folder of the demo. There are two animator files, which indicate that we can provide the same animator for present and dismiss, or provide respective animator respectively. If the animation effect is similar, you can share the same animator, the only difference is:

    • When present, add the Toview to the container view level.
    • When dismiss, remove the fromview from the container view level.

If you get dizzy with this large piece of code and knowledge, or if you don't use these specific knowledge for a while, you need to remember at least the basics and processes of custom animations:

    • Sets the transitioningdelegate of the View controller (Presentedviewcontroller) to which you want to jump
    • The object acting as a proxy can be either a Source view controller (Presentingviewcontroller) or an object that you create, and it needs to provide a animator object for the transition animation.
    • The animatetransition of the animator object is the core logic of the whole animation.

Interactive (Interactive) Transitions animation
We just said that when we set the Transitioningdelegate attribute of Toviewcontroller and present, Uikit will get animator from the proxy. There's also a detail here: Uikit also invokes the proxy's interactioncontrollerforpresentation: method to get the interactive controller, which, if nil, performs a non-interactive animation, which goes back to the previous section.

If you get an object that is not nil, then Uikit does not invoke the animator Animatetransition method, but instead invokes the interactive controller (remember the schematic of the animation agent described earlier, the interactive animation controller and the animator are lateral relationships) The Startinteractivetransition: Method.

An interactive animation, usually based on gesture actuation, produces a percentage of the animation complete to control the animation effect (the second animation effect in the GIF at the beginning of the article). The entire animation is no longer a one-time, coherent completion, but at any time can change the percentage or even cancel. This requires an interactive animation controller that implements the Uipercentdriveninteractivetransition protocol and animator work together. This looks like a very complex task, but Uikit has already encapsulated enough detail, we just need to define a time processing function (such as handling a sliding gesture) in the interactive animation controller and in, and then when we receive a new event, Calculates the percentage of animation completion and calls Updateinteractivetransition to update the animation progress.

Use the following code to briefly describe the entire process (delete some of the details and comments, please do not use this as the correct reference), the complete code refer to the Interactivity folder in the demo:

This is equivalent to Fromviewcontroller class Interactivityfirstviewcontroller:uiviewcontroller {//This is equivalent to Toviewcontroller lazy var interactivitysecondviewcontroller:interactivitysecondviewcontroller = Interactivitysecondviewcontroller ()// Defines a interactivitytransitiondelegate class as a proxy lazy var customtransitiondelegate:interactivitytransitiondelegate = Interactivitytransitiondelegate () override Func Viewdidload () {super.viewdidload () Setupview ()//mainly the layout of some UI controls , you can disregard its implementation details///set the animation agent, this agent is more complex, so we created a new proxy object rather than let self as a proxy interactivitysecondviewcontroller.transitioningdelegate = customtransitiondelegate}//Trigger gesture, also call animationbuttondidclicked method func interactivetransitionrecognizeraction (SE Nder:uiscreenedgepangesturerecognizer) {if sender.state = =.
    began {self.animationbuttondidclicked (sender)}} func animationbuttondidclicked (sender:anyobject) {
Self.presentviewcontroller (Interactivitysecondviewcontroller, Animated:true, Completion:nil)  }
}

 

Non-interactive animation agents only need to provide animator for present and dismiss, but in interactive animation agents, interactive animation controllers for present and dismiss are also required:

Class Interactivitytransitiondelegate:nsobject, Uiviewcontrollertransitioningdelegate {func Animationcontrollerforpresentedcontroller (Presented:uiviewcontroller, Presentingcontroller presenting: Uiviewcontroller, Sourcecontroller source:uiviewcontroller)-> uiviewcontrolleranimatedtransitioning? {return Interactivitytransitionanimator (Targetedge:targetedge)} func Animationcontrollerfordismissedcontroller (Dismissed:uiviewcontroller)-> uiviewcontrolleranimatedtransitioning?

  {return Interactivitytransitionanimator (Targetedge:targetedge)}///the first two functions and the implementation in fade demo are consistent///the latter two functions are used to implement interactive animation Func interactioncontrollerforpresentation (animator:uiviewcontrolleranimatedtransitioning)-> Uiviewcontrollerinteractivetransitioning? {return Transitioninteractioncontroller (Gesturerecognizer:gesturerecognizer, Edgefordragging:targetedge)} fun C Interactioncontrollerfordismissal (animator:uiviewcontrolleranimatedtransitioning)-> UIViewControllerIntEractivetransitioning?

 {return Transitioninteractioncontroller (Gesturerecognizer:gesturerecognizer, Edgefordragging:targetedge)}}

The code in animator is omitted, and it is similar to the animator in Non-interactive animations. Because interactive animation is just an icing on the cake, it must support non-interactive animations, such as in this case, the click button is still a non-interactive animation, but a gesture slide will trigger an interactive animation.

Class Transitioninteractioncontroller:uipercentdriveninteractivetransition {
  ///triggers this function when the gesture has a slide
  func Gesturerecognizedidupdate (gesturerecognizer:uiscreenedgepangesturerecognizer) {
    switch gesturerecognizer.state {case
    . Began:break case
    . Changed:self.updateInteractiveTransition (Self.percentforgesture (Gesturerecognizer))//gesture slip, update percent case
    . Ended:  //sliding end, judge whether more than half, if is to complete the remaining animation, otherwise cancel the animation
      if Self.percentforgesture (gesturerecognizer) >= 0.5 {
        Self.finishinteractivetransition ()
      }
      else {
        self.cancelinteractivetransition ()
      }
    Default:self.cancelInteractiveTransition ()
    }
  }
  private func percentforgesture (gesture: Uiscreenedgepangesturerecognizer)-> CGFloat {Let
    percent = calculated based on gesture return
    percent
  }
}

Interactive animations are implemented on the basis of non-interactive animations, and we need to create a subclass that inherits from the Uipercentdriveninteractivetransition type, and returns an instance object of that type in the animation agent.

In this type, the time change of the listening gesture (or download progress, and so on), and then call the Percentforgesture method to update the animation progress.

Transitions Coordinator and Uimodalpresentationcustom
You can also perform some synchronized, additional animations, such as the third example in a GIF at the beginning of the article, while you are animating the transitions. Presentedview and Presentingview can change their view levels and add extra effects (shadows, rounded corners). Uikit uses the Convert Coordinator to manage these additional animations. You can obtain the transition coordinator by using the Transitioncoordinator property of the view controller that requires animation effects, which exist only during the execution of the Transitions animation.

To complete the third example in GIF, we also need to use Uimodalpresentationstyle.custom instead. Fullscreen. Because the latter will remove the Fromviewcontroller, this is clearly not in line with demand.

When the present way for. Custom, we can also use Uipresentationcontroller more thorough control of the effect of the transition animation. A presentation controller has the following features:

    • Set the view size of the Presentedviewcontroller
    • Add a custom view to change the appearance of Presentedview
    • Provide a transition animation effect for any custom view
    • Responsive layout based on size class

You may think that. Fullscreen and other present styles are available to Swift for our implementation, they are. Special case of Custom. and. Custom allows us to more freely define transitions animation effects.

Uipresentationcontroller provides four functions to define the operation of the present and dismiss animations before and after the start:

    • When Presentationtransitionwillbegin:present will be executed
    • After the presentationtransitiondidend:present execution is complete
    • When Dismissaltransitionwillbegin:dismiss will be executed
    • After the Dismissaltransitiondidend:dismiss execution is complete

The following code briefly describes the implementation of the third animation effect in GIF, and you can view the completion code under the custom presentation folder of the demo:

This is equivalent to Fromviewcontroller class Custompresentationfirstviewcontroller:uiviewcontroller {//This is equivalent to Toviewcontroller l Azy var Custompresentationsecondviewcontroller:custompresentationsecondviewcontroller = Custompresentationsecondviewcontroller ()///create Presentationcontroller lazy var Custompresentationcontroller: Custompresentationcontroller = Custompresentationcontroller (presentedviewcontroller: Self.custompresentationsecondviewcontroller, presentingviewcontroller:self) override Func Viewdidload () {SUPER.VI Ewdidload () Setupview ()//is primarily the layout of some UI controls that can be ignored for their implementation details//Set Transitions animation agent Custompresentationsecondviewcontroller.transiti Oningdelegate = Custompresentationcontroller} override func didreceivememorywarning () {Super.didreceivememorywa
  Rning ()//Dispose of any of the can is recreated. } func animationbuttondidclicked () {Self.presentviewcontroller (Custompresentationsecondviewcontroller, Animated:t

 Rue, Completion:nil)}}

The focus is on how to implement the Custompresentationcontroller class:

Class Custompresentationcontroller:uipresentationcontroller, Uiviewcontrollertransitioningdelegate {var Presentationwrappingview:uiview? This view encapsulates the original view, adding shadow and rounded effects var dimmingview:uiview? = NIL//Alpha 0.5 Black Mask//Tell Uikit which view to add animation effect override Func Presentedview ()-> UIView?

{return Self.presentationwrappingview}} Four ways to customize the operation before and after a transition animation extension Custompresentationcontroller {override Func Presentationtransitionwillbegin () {// Set Presentationwrappingview and Dimmingview UI effects let Transitioncoordinator = Self.presentingViewController.transitionCoordinator () Self.dimmingview? Alpha = 0//Synchronization animation effects through the transition coordinator Transitioncoordinator? Animatealongsidetransition ({(context:uiviewcontrollertransitioncoordinatorcontext)-> Void in Self.dimmingView? . Alpha = 0.5}, Completion:nil}///present at the end, the Dimmingview and Wrappingview are emptied, and the temporary views are not used override Func Prese Ntationtransitiondidend (completed:bool) {if!completed {self.presentAtionwrappingview = Nil Self.dimmingview = nil}///dismiss start, make dimmingview completely transparent, this animation and the animation in animator occur simultaneously Override Func Dismissaltransitionwillbegin () {Let transitioncoordinator = Self.presentingViewController.transitionCo Ordinator () Transitioncoordinator? Animatealongsidetransition ({(context:uiviewcontrollertransitioncoordinatorcontext)-> Void in Self.dimmingView? . Alpha = 0}, Completion:nil)}///dismiss at the end of the Dimmingview and Wrappingview are emptied, these temporary views are not used override Func dismiss Altransitiondidend (Completed:bool) {if completed {Self.presentationwrappingview = nil Self.dimmingview

 = nil}} extension Custompresentationcontroller {}

In addition, this class also handles the logic associated with the child view layout. As an animation agent, you also need to provide the animator object for the animation, the detailed code please read in the demo's Custom presentation folder.

Uinavigationcontroller Transitions Animation
So far, all transition animations are applicable to present and dismiss, but Uinavigationcontroller can also customize the animation of transitions. The two are parallel, and many can be likened:

Class Fromviewcontroller:uiviewcontroller, uinavigationcontrollerdelegate {let
  toviewcontroller: Toviewcontroller = Toviewcontroller ()

  override func Viewdidload () {super.viewdidload () Setupview ()
    // Mainly the layout of some UI controls that can be ignored for implementation details

    self.navigationController.delegate = self
  }


Unlike Present/dismiss, the view controller now implements the Uinavigationcontrollerdelegate protocol, allowing itself to become a navigationcontroller agent. The agreement is similar to the previous Uiviewcontrollertransitioningdelegate agreement.

The Fromviewcontroller implementation of the Uinavigationcontrollerdelegate protocol is as follows:

Func Navigationcontroller (Navigationcontroller:uinavigationcontroller, 
   animationcontrollerforoperation Operation:uinavigationcontrolleroperation, 
           fromviewcontroller fromvc:uiviewcontroller, 
             ToViewController Tovc:uiviewcontroller) 
            -> uiviewcontrolleranimatedtransitioning? {
    if operation = =. Push {return
      pushanimator ()
    }
    if operation = =. Pop {return
      popanimator ()
    } return
    nil
  }

As for animator, there is no difference from the previous. Visible, a very good animator, not only can be used in Present/dismiss, can even be used in Push/pop.

Uinavigationcontroller can also add interactive transitions animations, and the principle is similar to the previous.

Summarize
For non-interactive animations, you need to set the Transitioningdelegate property of the Presentedviewcontroller, which needs to provide animator for present and dismiss. The duration and performance logic of the animation are defined in the animator.

For interactive animations, it is necessary to provide an interactive animation controller from the Transitioningdelegate property on a previous basis. Perform event handling in the controller, and then update the animation completion progress.

For custom animations, you can customize the effect before and after the animation by using four functions in Uipresentationcontroller, you can modify the size and appearance of the Presentedviewcontroller, and perform other animations synchronously.

Custom animation of the water is still relatively deep, this article is only suitable for beginners to learn to use, welcome to communicate with each other.

Related Article

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.