Toggle animations and interactive animations for IOS custom pages

Source: Internet
Author: User

Before iOS7, developers could only be limited to a uinavigationcontroller of subclasses, or overwrite it with custom animations, in order to find Push/pop animations for custom navigation controllers. But with the advent of iOS7, Apple has introduced new tools for developers to manage Uiviewcontroller switching in a more flexible way.

Push/pop animations for custom navigation bars

In order to make a custom animation switch based on Uinavigationcontroller, first build a simple project, the Rootviewcontroller of this project is a uinavigationcontroller, Uinavigationcontroller's Rootviewcontroller is a simple uiviewcontroller (called the Main page), A button on this uiviewcontroller can go into the next uiviewcontroller (called the detail page), We first implement two protocols on the Viewcontroller on the main page: Uinavigationcontrollerdelegate and uiviewcontrolleranimatedtransitioning, Then in Viewdidload the Navigationcontroller's delegate is set to self, so we know when the navigation bar push and pop, and then use a property to write down whether it is push or pop, like this:

Func Navigationcontroller (navigationcontroller:uinavigationcontroller!, animationcontrollerforoperation operation : Uinavigationcontrolleroperation, Fromviewcontroller fromvc:uiviewcontroller!, Toviewcontroller ToVC: uiviewcontroller!) uiviewcontrolleranimatedtransitioning! {    navigationoperation = Operation    return self}
This is a new way of iOS7, and this method requires you to provide a uiviewcontrolleranimatedtransitioningThat uiviewcontrolleranimatedtransitioningWhat the hell is it?

The

uiviewcontrolleranimatedtransitioning is a new addition to Apple's protocol, which is designed to use custom animations without affecting other properties of the view. Let you focus on the implementation of the animation itself, and then through the callback in the protocol to write custom animation code, that "what should happen in the switchover", responsible for the specific content of the switch, any object that implements this protocol is called the animation controller. you can use the protocol can be implemented by any object of this feature, so that the various animation effects encapsulated in different classes, as long as the user-friendly and management, you can play all means. I am here to make the main page to implement animation controller is also possible, because it is the navigation bar Rootviewcontroller, will always exist, I just write a custom push and pop animation code in it can be:

Uiviewcontrollertransitioningdelegatefunc transitionduration (transitioncontext: uiviewcontrollercontexttransitioning!) -Nstimeinterval {return 0.4}func animatetransition (transitioncontext:uiviewcontrollercontexttransitioning!) {Let Containerview = Transitioncontext.containerview () Let Toviewcontroller = Transitioncontext.viewcontrollerforke Y (uitransitioncontexttoviewcontrollerkey) Let Fromviewcontroller = Transitioncontext.viewcontrollerforkey (    Uitransitioncontextfromviewcontrollerkey) var destview:uiview!    var desttransform:cgaffinetransform!  if navigationoperation = = Uinavigationcontrolleroperation.push {Containerview.insertsubview (ToViewController.view, AboveSubview:fromViewController.view) Destview = Toviewcontroller.view Destview.transform = cgaffinetransf Ormmakescale (0.1, 0.1) Desttransform = Cgaffinetransformmakescale (1, 1)} else if navigationoperation = = Uinavig Ationcontrolleroperation.pop {ContainerviEw.insertsubview (Toviewcontroller.view, belowSubview:fromViewController.view) Destview = Fromviewcontroller.view If the IDE is Xcode6 BETA4+IOS8SDK, then set to 0 here, the animation will not be executed (not sure where the bug is) Desttransform = Cgaffinetransformmakescale (0.1,  0.1)} uiview.animatewithduration (Transitionduration (Transitioncontext), animations: {Destview.transform = Desttransform}, Completion: ({completed in Transitioncontext.completetransition (True)})}

The first method above returns the duration of the animation, and the following method is the exact place to implement the animation. The Uiviewcontrolleranimatedtransitioning protocol contains an object: Transitioncontext, which can get the context information of the switch, such as which VC switch to which VC. We get Containerview from Transitioncontext, which is a special container that will be animated in this container when switching , Uitransitioncontextfromviewcontrollerkey and Uitransitioncontexttoviewcontrollerkey is from which VC switch to which VC, easy to understand; There are also direct access to the view of Uitransitioncontextfromviewkey and Uitransitioncontexttoviewkey and so on.

I press push and pop to distinguish the animation simple, push the scale from small to large, pop scale from big to small, different operations, Toviewcontroller view hierarchy is not the same. Finally, when the animation is done, call completetransitionand tell Transitioncontext that your animation has ended, which is a very important method that must be called . The Containerview sub-view is not cleaned up at the end of the animation (such as removing the Fromviewcontroller view) because Transitioncontext is automatically cleaned up, so we do not need to do extra processing.

Note that the interactive return effect of the original navigation bar is not available, and if you want to use the original interactive return effect, return nil in the delegate method that returns the animation controller, such as:

if operation = = Uinavigationcontrolleroperation.push {    navigationoperation = operation    return Self}return Nil
Then in the Viewdidload, objective-c directly self.navigationController.interactivePopGestureRecognizer.delegat = self on the line, In addition to NavigationController.interactivePopGestureRecognizer.delegate = self, Swift Also on self to affirm the realization of uigesturerecognizerdelegate this agreement, although the implementation of you did not achieve.

A simple custom navigation bar Push/pop animation is complete.

Custom modal Present/dismiss animation custom modal present and dismiss animations are similar to the previous one, we need to provide an animation manager, we use the detail page to display a modal page, the details page as the animation manager:
Func transitionduration (transitioncontext:uiviewcontrollercontexttransitioning!), Nstimeinterval {return 0.6} Func animatetransition (transitioncontext:uiviewcontrollercontexttransitioning!) {Let Containerview = Transitioncontext.containerview () Let Toviewcontroller = Transitioncontext.viewcontrollerf Orkey (uitransitioncontexttoviewcontrollerkey) Let Fromviewcontroller = Transitioncontext.viewcontrollerforkey (    Uitransitioncontextfromviewcontrollerkey) var destview:uiview! var desttransfrom = cgaffinetransformidentity Let screenheight = Uiscreen.mainscreen (). bounds.size.height If mod Alpresentingtype = = modalpresentingtype.present {Destview = Toviewcontroller.view Destview.transform = CGAf Finetransformmaketranslation (0, ScreenHeight) containerview.addsubview (Toviewcontroller.view)} else if modalPre Sentingtype = = Modalpresentingtype.dismiss {Destview = Fromviewcontroller.view Desttransfrom = CGAffineTran SfoRmmaketranslation (0, ScreenHeight) containerview.insertsubview (Toviewcontroller.view, Belowsubview:fromviewcontro  Ller.view)} uiview.animatewithduration (Transitionduration (Transitioncontext), delay:0, usingSpringWithDamping: 0.6, initialspringvelocity:0, options:UIViewAnimationOptions.CurveLinear, animations: {destview.transform = Desttransfrom}, Completion: {completed in Transitioncontext.completetransition (True)})}
Animation part with a iOS7 of the spring animation, usingspringwithdamping the value of the smaller, the more obvious, the animation of the other places similar to the previous, not the same as before the main page in addition to do animation manager, The Uinavigationcontrollerdelegate protocol is also implemented because we are animating the custom navigation bar, where custom modal animations are required to implement another protocol: uiviewcontrollertransitioningdelegate, this protocol is similar to the previous Uinavigationcontrollerdelegate protocol, is to return an animation manager, iOS7 total of four, there are two interactive first, we only need to implement another two can:
Func Animationcontrollerforpresentedcontroller (presented:uiviewcontroller!, Presentingcontroller presenting: uiviewcontroller!, Sourcecontroller source:uiviewcontroller!) uiviewcontrolleranimatedtransitioning! {    Modalpresentingtype = modalpresentingtype.present    return self}func Animationcontrollerfordismissedcontroller (dismissed:uiviewcontroller!) uiviewcontrolleranimatedtransitioning! {    Modalpresentingtype = Modalpresentingtype.dismiss    return self}
I also use a property to write down whether it is present or dismiss, and then return to self. Because I am using the storyboard, so I need to set the transitiondelegate in the Prepareforsegue method:
Override Func Prepareforsegue (segue:uistoryboardsegue!, sender:anyobject!) {Let    modal = Segue.destinationviewcontroller as Uiviewcontroller    modal.transitioningdelegate = self}
Set the Transitiondelegate property for the VC that needs to perform the custom animation. As a result, a custom animation for the modal VC is also completed.
Interactive animations for custom navigation bars are similar to animation controllers, and we have implemented uiviewcontrollerinteractivetransitioningThe object of the agreement is called Interactive Controller, the most common is to apply the interactive controller to the navigation bar back gesture return, and if you want to implement a custom interactive animation, we have two ways to accomplish: To implement an interactive controller, Or use the Uipercentdriveninteractivetransition class provided by iOS as an interactive controller.
Using uipercentdriveninteractivetransition we use Uipercentdriveninteractivetransition to complete the interactive animation of the navigation bar. First look at the definition of uipercentdriveninteractivetransition:

In fact, this class is an interactive controller that implements the Uiviewcontrollerinteractivetransitioning protocol, and we use it to easily add an interactive animation to the animation controller. Call Updateinteractivetransition: update progress; call Cancelinteractivetransition to cancel the interaction and return to the state before the switchover ; Call Finishinteractivetransition notifies the context that the interaction is complete, as with completetransition. We apply the interactive animation to the detail page back to the main page, because the role of the previous animation manager is the main page, the Navigation controller's delegate can only have one at a time, where the role of the interactive controller is also the main page to assume. First, add a gesture recognizer:

Let Poprecognizer = Uiscreenedgepangesturerecognizer (target:self, Action:selector ("Handlepoprecognizer:")) Poprecognizer.edges = UIRectEdge.Leftself.navigationController.view.addGestureRecognizer (Poprecognizer)
The Uiscreenedgepangesturerecognizer inherits from the Uipangesturerecognizer, detects gestures that slide from the edge of the screen, and sets the edges to the left to detect. Then implement Handlepoprecognizer:

Func Handlepoprecognizer (Poprecognizer:uiscreenedgepangesturerecognizer) {var progress =    Poprecognizer.translationinview (Navigationcontroller.view). X/navigationcontroller.view.bounds.size.width progress = min (1.0, max (0.0, progress)) println ("\ (Progress)") if poprecognizer.state = = Uigesturerecognizerstat E.began {println ("began") Self.interactivepoptransition = Uipercentdriveninteractivetransition () sel F.navigationcontroller.popviewcontrolleranimated (True)} else if poprecognizer.state = = uigesturerecognizerstate.changed {self.interactivepoptransition?. Updateinteractivetransition (Progress) println ("Changed")} else if poprecognizer.state = = Uigesturerecognizersta Te. Ended | | Poprecognizer.state = = uigesturerecognizerstate.cancelled {If progress > 0.5 {self.interactivepoptr Ansition?. Finishinteractivetransition ()} else {self.interactivepoptransition?.     Cancelinteractivetransition ()   } println ("Ended | | Cancelled ") Self.interactivepoptransition = nil}}
I used an instance variable to refer to Uipercentdriveninteractivetransition, which was created only when it was needed, otherwise, in normal push/pop, even if it was just a click operation and no gesture was identified, will also enter the interaction (you can also make some judgments when asking you to return to the interactive controller, blocking by returning nil, but this is obviously too cumbersome). When gesture recognition when we call pop, the user gesture changes, call update updates, whether it is the end or cancel, are judged to go to the next page or return to the previous page, complete all of this after the interaction controller cleanup.

Now that we have an interactive controller object, just give it to the navigation controller, and another way we implement Uinavigationcontrollerdelegate:

Func Navigationcontroller (navigationcontroller:uinavigationcontroller!, Interactioncontrollerforanimationcontroller animationcontroller:uiviewcontrolleranimatedtransitioning!) uiviewcontrollerinteractivetransitioning! {    return self.interactivepoptransition}
We have finished the work of returning to the previous page from the details page through a custom interactive animation.

Use Uipercentdriveninteractivetransition's Demo


Custom interaction Controller I mentioned before, uipercentdriveninteractivetransition actually realized. uiviewcontrollerinteractivetransitioningprotocol, as long as the object that implements this protocol can be called an interactive controller, if we want to manage the animation more precisely and understand the details of processing, we need to implement uiviewcontrollerinteractivetransitioningAgreement. The Uiviewcontrollerinteractivetransitioning protocol has a total of three methods, where Startinteractivetransition: is the method that must be implemented, in which we initialize the state of the animation:
Func startinteractivetransition (transitioncontext:uiviewcontrollercontexttransitioning!) {    Self.transitioncontext = transitioncontext let        containerview = Transitioncontext.containerview ()    Let Toviewcontroller = Transitioncontext.viewcontrollerforkey (uitransitioncontexttoviewcontrollerkey) Let    Fromviewcontroller = Transitioncontext.viewcontrollerforkey (uitransitioncontextfromviewcontrollerkey)        Containerview.insertsubview (Toviewcontroller.view, BelowSubview:fromViewController.view)        Self.transitingview = Fromviewcontroller.view}
There is no animation involved, just adding the view that needs to be switched to the context. Animation section We are still consistent with the previous interface with Uipercentdriveninteractivetransition, adding several methods:
Func updatewithpercent (percent:cgfloat) {Let scale = CGFloat (FABSF (percent-cgfloat))) 1.0? . Transform = Cgaffinetransformmakescale (scale, scale) Transitioncontext?. Updateinteractivetransition (percent)}func Finishby (cancelled:bool) {if cancelled {uiview.animatewithduration ( 0.4, animations: {self.transitingview!. Transform = cgaffinetransformidentity}, Completion: {completed in self.transitioncontext!. Cancelinteractivetransition () self.transitioncontext!. Completetransition (False)})} else {uiview.animatewithduration (0.4, animations: {print (self . Transitingview) self.transitingview!.            Transform = Cgaffinetransformmakescale (0, 0) print (Self.transitingview)}, Completion: {completed in self.transitioncontext!. Finishinteractivetransition () self.transitioncontext!. Completetransition (True)})}}
Updatewithpercent: Method is used to update the Transform property of the view, Finishby: The method is mainly used to determine whether to go to the next page or return to the previous page, and tell Transitioncontext the current state, And the final animation of the view that is currently in scale. Here the Transitioncontext and Transitingview can be obtained in the previous processing gesture recognition code, I will update the code inside, and become the following:
Func Handlepoprecognizer (Poprecognizer:uiscreenedgepangesturerecognizer) {var progress =    Poprecognizer.translationinview (Navigationcontroller.view). X/navigationcontroller.view.bounds.size.width progress = min (1.0, max (0.0, progress)) println ("\ (Progress)") if poprecognizer.state = = Uigesturerecognizerstat E.began {println ("began") Istransiting = True//self.interactivepoptransition = Uipercentdrivenint Eractivetransition () self.navigationController.popViewControllerAnimated (TRUE)} else if poprecognizer.state = = uigesturerecognizerstate.changed {//self.interactivepoptransition?. Updateinteractivetransition (Progress) updatewithpercent (progress) println ("Changed")} else if Poprecogni Zer.state = = Uigesturerecognizerstate.ended | | Poprecognizer.state = = uigesturerecognizerstate.cancelled {//if progress > 0.5 {//Self.interact Ivepoptransition?. Finishinteractivetransition ()//} ELSE {//self.interactivepoptransition?. Cancelinteractivetransition ()//} Finishby (Progress < 0.5) println ("Ended | | Cancelled ") Istransiting = False//self.interactivepoptransition = nil}}
An additional Boolean variable istransiting is also used to identify whether the gesture is currently being identified, in order to return to self when the interaction controller is returned:
Func Navigationcontroller (navigationcontroller:uinavigationcontroller!, Interactioncontrollerforanimationcontroller animationcontroller:uiviewcontrolleranimatedtransitioning!) uiviewcontrollerinteractivetransitioning! {    If!self.istransiting {        return nil    }    return self}
This completes the custom interaction controller. It can be found that the basic process is consistent with the use of uipercentdriveninteractivetransition, Uipercentdriveninteractivetransition is mainly to help us encapsulate the initialization of the transitioncontext and calls to it, and so on, just the animation part needs us to deal with the extra.
Demo using custom Interactive controller(generally failed when uploading to my resources page, so it can only be uploaded to GitHub)

Finally, attach a picture, which makes it easier to distinguish between the several protocols with similar names:



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.