iOS animation advanced-hand touch teach you to write Slack Loading animation

Source: Internet
Author: User

If mobile access is poor, you can visit my personal blog

A few days ago read a blog about animation called Hand to teach you to write Slack of the Loading animation, looking very flashy, but it is the Android version, thinking of The imitation of writing an iOS version, the following is I write this animation decomposition ~

The usual first and demo address:

When I first saw this animation, there were two schemes in my mind, one of which was to draw drawRect it, and then to keep drawing the line, and the CADisplayLink second CAShapeLayer was CAAnimation to achieve the animation effect by matching. Think twice about using the latter, because the former need to calculate a lot, more complex, and after testing the former compared to the latter consumes more CPU, the following will be my idea write down:

Related configuration and initialization methods

Before we write this animation, we write the attributes we need first, such as the thickness of the lines, the time of the animation, and so on, and the following are the relevant configuration and initial methods:

    //width of line    varLinewidth:cgfloat =0    //Length of line    varLinelength:cgfloat =0    //Margin    varMargin:cgfloat =0    //Animation time    varDuration:double =2    //time interval of animation    varInterval:double =1    //Four lines of color    varColors:[uicolor] = [Uicolor.init (RGBA:"#9DD4E9"), Uicolor.init (RGBA:"#F5BD58"), Uicolor.init (RGBA:"#FF317E"), Uicolor.init (RGBA:"#6FC9B5")]//State of the animation    Private(Set)varStatus:animationstatus =. Normal//Four lines    Private varLines:[cashapelayer] = []enumAnimationstatus {//Normal status         CaseNormal//In animation         CaseAnimating//Pause         CasePause}//mark:initial MethodsConvenience init (fram:cgrect, colors: [Uicolor]) {self.init () Self.frame = frame Self.colors = Col ORS Config ()}OverrideInit (frame:cgrect) {super.init (frame:frame) config ()} required init? (Coder Adecoder:nscoder) {super.init (Coder:adecoder) config ()}PrivateFuncConfig() {linelength = max (Frame.width, frame.height) linewidth = linelength/6.0margin = linelength/4.5+ linewidth/2Drawlineshapelayer () transform = cgaffinetransformrotate (cgaffinetransformidentity, Angle (- -))    }
Draw lines with Cashapelayer

When I saw this line, I thought about it, CAShapeLayer because CAShapeLayer it was completely achievable, and its strokeEnd properties could be used to animate the length of the line, and to draw four lines of code below:

//mark: Drawing lines    /** Draw four lines * /    PrivateFuncDrawlineshapelayer() {//Start pointLet StartPoint = [Point (linewidth/2, Y:margin), point (Linelength-margin, y:linewidth/2), point (linelength-linewidth/2, Y:linelength-margin), point (margin, y:linelength-linewidth/2)]//End pointLet EndPoint = [Point (linelength-linewidth/2, Y:margin), point (Linelength-margin, y:linelength-linewidth/2), point (linewidth/2, Y:linelength-margin), point (margin, y:linewidth/2)] forI in0... 3{Let Line:cashapelayer = Cashapelayer () line.linewidth = linewidth Line.linecap = Kcalinecapround line.opacity =0.8Line.strokecolor = Colors[i]. Cgcolor Line.path = Getlinepath (Startpoint[i], endpoint:endpoint[i]). Cgpath Layer.addsublayer (line) lines.append (line)}}/** Get line path-parameter startPoint: Start point-parameter endPoint: End point-Returns: Line path * /    PrivateFuncGetlinepath(Startpoint:cgpoint, Endpoint:cgpoint), Uibezierpath {Let path = Uibezierpath () path.movetopoint (STA Rtpoint) Path.addlinetopoint (endPoint)returnPath}PrivateFunc Point(X:cgfloat, y:cgfloat), Cgpoint {returnCgpointmake (x, y)}PrivateFuncAngle(angle:double), CGFloat {returnCGFloat (Angle * (m_pi/ the))    }

After the implementation of the same effect is the same ~ ~ ~

Animation decomposition

After analysis, the animation can be divided into four steps:

    • Rotation animation of the canvas, rotating two circles
    • The line is executed by a shorter animation, a canvas-selected animation, and a circle of rotation ends
    • The displacement animation of the line, the line gradually toward the middle, and then the brush after rotating a circle of time to execute, two laps when the end
    • The line is animated by a short, long animation, when the canvas is rotated two times to execute
First step canvas rotate animation

Here we use the CABasicAnimation base animation, which keyPath acts on the canvas transform.rotation.z , rotates with the z-axis as the target, and the following is the code:

//MARK: 动画步骤    /**     旋转的动画,旋转两圈     */    privateangleAnimation() {        let angleAnimation                 "transform.rotation.z")        angleAnimation.fromValue           = angle(-30)        angleAnimation.toValue             = angle(690)        angleAnimation.fillMode            = kCAFillModeForwards        false        angleAnimation.duration            = duration        angleAnimation.delegate            = self        "angleAnimation")    }
The second step of the line by the long short animation

Here we still use the CABasicAnimation basic animation, keyPath acting on the properties of the line strokeEnd , let the strokeEnd line from 1 to zero to achieve the length of the animation, the following is and code:

The first step of the/** line animation, the line length from long to short * /    PrivateFuncLineanimationone() {Let Lineanimationone = Cabasicanimation.init (keypath:"Strokeend") Lineanimationone.duration = duration/2Lineanimationone.fillmode = Kcafillmodeforwards Lineanimationone.removedoncompletion =falseLineanimationone.fromvalue =1Lineanimationone.tovalue =0         forI in0... 3{Let Linelayer = Lines[i] Linelayer.addanimation (Lineanimationone, Forkey:"Lineanimationone")        }    }
Displacement animation of the third step line

Here we also use the CABasicAnimation basic animation, keyPath acting on the line transform.translation.x and transform.translation.y attributes, to achieve the effect of the middle, the following is and the code:

The second step of the/** line animation, the line to the middle translation * /    PrivateFuncLineanimationtwo() { forIinch 0... 3{varKeyPath ="Transform.translation.x"            ifi%2==1{KeyPath ="TRANSFORM.TRANSLATION.Y"} LetLineanimationtwo = Cabasicanimation.init (keypath:keypath) lineanimationtwo.begintime = CACurrentMediaTime () + duration/2Lineanimationtwo.duration = duration/4Lineanimationtwo.fillmode = Kcafillmodeforwards Lineanimationtwo.removedoncompletion =falseLineanimationtwo.autoreverses =trueLineanimationtwo.fromvalue =0            ifI <2{Lineanimationtwo.tovalue = linelength/4}Else{Lineanimationtwo.tovalue =-linelength/4} LetLinelayer = Lines[i] Linelayer.addanimation (Lineanimationtwo, Forkey:"Lineanimationtwo")        }//ratio on both sides of the triangle         LetScale = (LineLength-2*margin)/(Linelength-linewidth) forIinch 0... 3{varKeyPath ="TRANSFORM.TRANSLATION.Y"            ifi%2==1{KeyPath ="Transform.translation.x"} LetLineanimationtwo = Cabasicanimation.init (keypath:keypath) lineanimationtwo.begintime = CACurrentMediaTime () + duration/2Lineanimationtwo.duration = duration/4Lineanimationtwo.fillmode = Kcafillmodeforwards Lineanimationtwo.removedoncompletion =falseLineanimationtwo.autoreverses =trueLineanimationtwo.fromvalue =0            ifi = =0|| i = =3{Lineanimationtwo.tovalue = linelength/4* scale}Else{Lineanimationtwo.tovalue =-linelength/4* scale} LetLinelayer = Lines[i] Linelayer.addanimation (Lineanimationtwo, Forkey:"Lineanimationthree")        }    }
Fourth Step line Restore the original length of the animation

Here we still use the CABasicAnimation basic animation, keyPath acting on the properties of the line strokeEnd , let the strokeEnd line from 0 to one to achieve the length of the animation, the following is and code:

The third step of the/** line animation, the line from the short variable length * /    PrivateFuncLineanimationthree() {//Line Moving animationLet Lineanimationfour = Cabasicanimation.init (keypath:"Strokeend") Lineanimationfour.begintime = Cacurrentmediatime () + Duration lineanimationfour.duration = duration/4Lineanimationfour.fillmode = Kcafillmodeforwards Lineanimationfour.removedoncompletion =falseLineanimationfour.fromvalue =0Lineanimationfour.tovalue =1         forI in0... 3{ifi = =3{lineanimationfour.delegate = self} Let Linelayer = Lines[i] Linelayer.a Ddanimation (Lineanimationfour, Forkey:"Lineanimationfour")        }    }
The final step is to combine the animations.

About the animation mix I didn't use CAAnimationGroup , because these animations are not added to the same layer, plus the animation type a bit more trouble, I have animated beginTime properties to control the order of the animation, but also added animation pause and continue the function, effects and code see:

//mark:public Methods    /** Start animation * /Func startanimation () {angleanimation () Lineanimationone () lineanimationtwo () Lineanimationth REE ()}/** Pause Animation * /Func pauseanimation () {layer.pauseanimation () forLinelayer in lines {linelayer.pauseanimation ()} status =. Pause}/** Continue animation * /Func resumeanimation () {layer.resumeanimation () forLinelayer in lines {linelayer.resumeanimation ()} status =. animating} extension Calayer {//Pause animationFunc pauseanimation () {//Convert the current time cacurrentmediatime to the time on the layer, converting the parent to localtimeLet Pausetime = ConvertTime (Cacurrentmediatime (), Fromlayer:nil)//Set the Timeoffset of layer and use it to continue OperationTimeoffset = Pausetimethe ratio of//localtime to Parenttime is 0, which means the localtime is pausedSpeed =0; }//Resume animationFunc resumeanimation () {Let pausedtime = timeoffset speed =1Timeoffset =0; BeginTime =0        //Calculate pause TimeLet Sincepause = ConvertTime (Cacurrentmediatime (), Fromlayer:nil)-Pausedtime//local time vs. BeginTimeBeginTime = Sincepause}}//mark:animation Delegate    OverrideFunc Animationdidstart (anim:caanimation) {ifLet animation = Anim as? cabasicanimation {ifAnimation.keypath = ="Transform.rotation.z"{status =. Animating}}}OverrideFunc animationdidstop (anim:caanimation, finished Flag:bool) {ifLet animation = Anim as? cabasicanimation {ifAnimation.keypath = ="Strokeend"{ifFlag {status =. Normal Dispatch_after (Dispatch_time (Dispatch_time_now, Int64 (interval) * Int64 (NSEC_PER_SEC)), dispatch _get_main_queue (), {ifSelf.status! =.                animating {self.startanimation ()}}) }            }        }    }//mark:override    OverrideFunc touchesended (touches:set<uitouch>, withevent event:uievent?) {Switch Status { Case. Animating:pauseanimation () Case. Pause:resumeanimation () Case. Normal:startanimation ()}}
Summarize

The animation looks very complex, but carefully divided out also so that, in the animation before you want to think about the steps of animation, this is the key, I hope you can learn something through this blog, what good suggestions can be put forward at any time, thank you for reading ~~demo address

iOS animation advanced-hand touch teach you to write Slack Loading animation

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.