Customizing the switch process

Source: Internet
Author: User

Remcarpediem
Contact information: segmentfault,csdn, Pinterest

Please indicate the author, the source of the article, the link, the copyright belongs to the author.

? Some time ago, I saw an article about Android animation Android View imitation iOS switchbutton Material Design, like the article author's pen wind, but everyone's pen wind is different, But I did implement a similar switch component, the project address is Https://github.com/ztelur/FunSwitch, use this article to explain the implementation process and mechanism.

Introduction

My custom switch is to mimic llswitch on GitHub, whose UI design comes from Dribbble, which links to touch me as follows

Custom view functions that require overloading

? We all know that to View customize the view for the parent class, we need to overload a series of functions, so let's take a look at these functions in order of invocation. The list of functions that need to be overloaded is as follows:

    • onMeasure
    • onSizeChanged
    • onDraw
    • onTouchEvent
    • onSaveInstanceState
    • onRestoreInstanceState

? The first is the onMeasure function, which determines the length and height of the custom view. For the switch in this article, we make it as wide as a fixed scale size, so the refactoring function is very simple to implement. This function determines only the length and height of the measurement, not the length and height shown by the final view .

@OverrideprotectedvoidonMeasure(intint heightMeasureSpec) {    super.onMeasure(widthMeasureSpec, heightMeasureSpec);    int width = MeasureSpec.getSize(widthMeasureSpec);    int height = (int) (width * DEFAULT_WIDTH_HEIGHT_PERCENT);    setMeasuredDimension(width,height);}

? Then the onLayout function to be called after the view determines the true size () onSizeChanged . After this function is called, the draw function may be called, so we usually calculate the data we need to draw in this function.
? Next is the draw function, in which we draw various images to form the UI of the view. It is important to note that this function is frequently called, so do not perform time-consuming operations within the function.
The last is the onTouchEvent function, which is called when the user touches the screen, mainly for the touch processing of the view, because our custom switch supports the simple touch event, only supports the Click event, so the implementation of this function is also relatively simple.
? Finally, there are two functions that involve view state saving. We all know that, in some cases, the activity will be destroyed and re-established, such as when you rotate the screen. At this point, you need to save some of the view's property data in case you re-establish the view and use it to restore the previous view. you should be aware that it is not enough to overload these two functions, but also to set the view ID and call the setsaveenabled function .
? Let's move on to implementing this custom component in a single step.

Track-and-field background

? Let's take a look at the switch background, which is a shape like track and field runway, consisting of two halves and a rectangle, let's first look at how to draw such a pattern. We use it Path to construct the pattern, and then we draw it, and the code looks like this:

    @Override    protected void onsizechanged(intWintHintOLDW,intOLDH) {Super. onsizechanged (W, H, OLDW, OLDH);//todo: And padding's problem!!! Mwidth = W; Mheight = h;floattop =0;floatleft =0;floatBottom = h*0.8F///0.2 space below to draw shadows        floatright = W; RECTF BACKGROUNDRECF =NewRECTF (Left,top,bottom,bottom); Mbackgroundpath =NewPath ();//todo:???????????Mbackgroundpath.arcto (BACKGROUNDRECF, -, the);        Backgroundrecf.left = Right-bottom;        Backgroundrecf.right = right; Mbackgroundpath.arcto (BACKGROUNDRECF, the, the);        Mbackgroundpath.close (); ........    }@Override    protected void OnDraw(Canvas canvas) {Super. OnDraw (canvas);        Drawbackground (canvas);    Drawforeground (canvas); }Private void Drawbackground(Canvas canvas)        {Mpaint.setcolor (Mcurrentcolor);        Mpaint.setstyle (Paint.Style.FILL);        Canvas.drawpath (Mbackgroundpath,mpaint);    Mpaint.reset (); }

? We use the arcTo(RectF oval, float startAngle, float sweepAngle) function here to draw the track and field pattern. This function, need to pass in a RECTF object, the circle that will be drawn is the inscribed circle of the rectangle represented by this object, we just calculate the coordinates of the upper and lower left and right four points of this rectangle. We first calculate the rectangle needed to draw the left semicircle, then the function after the two parameters are 90, and 180. Note that in this function, the positive direction of the angle is clockwise, which is startAngle 90, which is the direction represented by the angle of 270 in our mathematical coordinate system.
? Because path will automatically connect the lines between points, so we just need to draw the curve of the right semicircle.
? We only need to translate the rectangle that draws the left circular curve to a certain distance, so we can draw the right curve. So the right edge of the rectangle is equal to the entire view right , because the rectangle is long bottom , so the left edge of the rectangle is right-bottom . Then call arcTo the function again and this time the starting angle becomes 270.
The last Path function called close , so that the top of the two-segment arc connected together, the formation of the above track and field pattern.

Draw Face Graphics

The smiley face pattern seems complex, in fact, a few graphics together. The first is a big circle, then the two oval eyes inside, then the mouth. We just need to draw these figures out in the right place.
? Similar to the order in which the background graphic is drawn, we first onSizeChanged calculate the correlation function in the function.
? The first is the drawing of the big round face, we still use the drawPath function, but this time the Path object only draws a circle, while the eyes are using the drawOval function to spend the ellipse, and the last use drawRect to draw the rectangle.

Switch Animations

? When we look at the animated effect of custom switch, we can see that there are mainly three parts of the animation effect:

    • Background color animation change.
    • The translation and rotation of the face pattern can be seen to be equivalent to a 360 degree rotation of the face level.
    • Facial expression animation, blink eyes and mouth open.

? Because the animation involves a lot of operations, so we choose to use ValueAnimator the animation implementation of the +, AnimatorUpdateListener recorded in the function of the onAnimationUpdate current animatedValue , and then call the invalidate function to let the interface redraw, in the drawing interface calculation data, using the recorded values, resulting in an animated effect.

    Private void startcloseanimation() {mvalueanimator = Valueanimator.offloat (Normal_anim_max_fraction,0);        Mvalueanimator.setduration (moffanimationduration); Mvalueanimator.addupdatelistener ( This); Mvalueanimator.addlistener ( This);        Mvalueanimator.setinterpolator (Minterpolator);        Mvalueanimator.start ();    Startcoloranimation (); }@Override     Public void onanimationupdate(Valueanimator animation) {manimationfraction = (float) Animation.getanimatedvalue (); Invalidate ();//Key steps to generate animations}

? So, the final animation problem becomes the problem of drawing still images, we mAnimationFraction draw different images according to different values.
? Let's describe the logic of some of the more critical animations.

Face rotation Animation

In fact, this facial animation is still relatively difficult to achieve, mainly the rotation of the effect of no direct API can be achieved. Our animation just gives the user the illusion of turning the face. Since the face pattern is a large circle plus an ellipse and a rectangle that acts as the eye and mouth, we can move the eyes and mouth in the direction of rotation, let them pan out the great circle, and then shift from another direction to the big circle after a certain amount of time, eventually returning to the original position. This achieves a face rotation effect.
How do you move your eyes and mouth to the edge of a great circle and disappear? And it's disappearing as part of the move? Here we use another way of thinking, using a clipPath function to crop the canvas, leaving only the pattern within the circle. In this way, when the eyes and mouth move out of the great circle, it will gradually disappear.
? As for how to translate the eyes and mouth? The first thought of the method must be based on the mAnimationFraction calculation of their position, and then draw them in the corresponding position, but this is not the optimal method, we can draw these images, the canvas is translated, so that we draw the eyes and mouth of the function will not be involved mAnimationFraction , Implementation is relatively straightforward.

 Public void Drawface(Canvas canvas,floatFraction) {Mpaint.setantialias (true);//Face backgroundMpaint.setcolor (Mfacecolor);        Mpaint.setstyle (Paint.Style.FILL); Canvas.drawpath (Mfacepath,mpaint);//crop and pan the canvas before drawing the eye facial featuresTranslateandclipface (canvas,fraction);        DrawEye (canvas,fraction);    Drawmouth (canvas,fraction); }Private void Translateandclipface(Canvas canvas,floatFraction) {//Cut out the parts that are beyond the face. Canvas.clippath (Mfacepath);floatFacetransition;//todo: Reasonable rotation interval, the eye appears and disappears the time ratio is 1:1, therefore when fraction=0.25, should only display the side face, calculates the facetransition.         if(Fraction >=0.0F && Fraction <0.5f) {facetransition = fraction * Mfaceradius *4; }Else if(Fraction <=normal_anim_max_fraction) {facetransition =-(normal_anim_max_fraction-fraction) * Mfaceradius *4; }Else if(Fraction <= (normal_anim_max_fraction+face_anim_max_fraction)/2) {facetransition = (fraction-normal_anim_max_fraction) * Mfaceradius *2; }Else{facetransition = (face_anim_max_fraction-fraction) * Mfaceradius *2; } canvas.translate (Facetransition,0); }
Blink and change smiley animation

The blink of an eye animation is very simple, we only need to draw the eye before drawing the canvas to zoom, and then after the drawing to play the eye, after the canvas is transformed back. But then I found that the center point of the canvas scaling was not easy to confirm, so the mAnimationValue ellipse size was scaled using the method of calculating the ellipse data.
The animation is mainly the animation effect of the mouth, in the static situation, we use drawRect to draw the mouth graphics, but in the animation process, we use drawPath and quadTo to co-draw the mouth shape.
?Path quadTois used to draw the Bezier curve, see the Bezier curve of path for specific use. We mainly use its second-order curve version, which is two data points, one control point. We calculated the two data points, A/b, that is, the upper-left and upper-right points of the rectangle in the stationary state, and then calculates the coordinates of the mAnimationValue control point C, and then finishes the drawing.

The drawing of the mouth pattern is shown below.

    Private void Drawmouth(Canvas canvas,floatFraction) {...//Mouth        if(Fraction <=0.75) {//Canvas.drawrect (Mouthleft, mouthtop, Mouthleft + mouthwidth, Mouthtop + mouthheight, mpaint); }Else{Path PATH =NewPath (); Path.moveto (Mouthleft,mouthtop);floatControlx = Mouthleft + mouthwidth/2;floatControly = mouthtop + mouthheight + mouthheight * the* (Fraction-0.75f);            Path.quadto (Controlx,controly,mouthleft+mouthwidth,mouthtop);            Path.close ();        Canvas.drawpath (Path,mpaint); }    }
Summary

? In fact, there are some details I did not say in this article, on the one hand, because it is too complicated to tell, or everyone to check the code is better, on the other hand, I feel that their way of implementation is not very good, it is not here caught dead.
The project has not been fully completed, such as custom listener and custom attribute related logic is not added, I hope interested students can study the code and improve it. Project address touch me on my github.

Customizing the switch process

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.