Android Custom View Bounceprogressbar

Source: Internet
Author: User
Tags cos sin

A few days ago downloaded a long time useless desktop version of the cool dog to use, found that the loading of songs waiting progress bar effect is good (personal feeling), as follows:




Then take advantage of this weekend two days of cold weather, nest in the dormitory put down piles of operating system operations (visual to copy a lesson of a lot of text ... Ah ...) Resolutely decided to tinker it out, the final effect is as follows (total feeling a bit discordant ah ·) :




The contrast can be seen is more of the shape of the choice and use of pictures, then the next step is its implementation process.

Suggestions for customizing view implementations see Guo Shen's Blog (View series 4): Android Layoutinflater Principle Analysis, take you step by step to understand the view (a) and the big corn this: Android Custom View--onmeasure, Measurespec Source Process Ideas detailed


Custom properties

Custom view generally uses the properties of the view itself, and overriding existing controls is not necessary. Well, then what's the unique attribute of our Bounceprogressbar? The first thing to be clear is that here Bounceprogressbar does not provide the implementation of specific progress performance. Then think about it: it needs the size of each image, called singlesrcsize, the type is dimension, and the speed of jumping up and down, called velocity, the type is integer, shape, called shape, Type is an enumeration type, providing the implementation of these shapes, original, Circle, Pentagon, rhombus, Heart are all known to know, and finally the required image resources, called src, type Reference|color, This can be a picture or color value in the drawable.

With the required attributes, in the values folder to build a resource file (the name is arbitrary, see the name is good) to define these attributes, such as, the code may be some English, and the level of some slag, but generally explained in front:

<?xml version= "1.0" encoding= "Utf-8"?><resources> <declare-styleable name= "Bounceprogressbar" > <!--the single child size--<attr name= "singlesrcsize" format= "Dimension"/> <!--the Bou NCE animation one-way duration-<attr name= "Speed" format= "integers"/> <!--the child count,        Originally wanted to be able to customize the number, but temporarily personal implementation of some trouble, so do not add this--<!--<attr name= "Count" format= "integer" min= "1"/>- <!--the Progress child shape--<attr name= "shape" format= "enum" > <enum name= "original            "value=" 0 "/> <enum name=" Circle "value=" 1 "/> <enum name=" Pentagon "value=" 2 "/>        <enum name= "Rhombus" value= "3"/> <enum name= "Heart" value= "4"/> </attr>    <!--the Progress drawable resource--<attr name= "src" format= "Reference|color" ></attr> </declare-styleable&gT;</resources> 

Then first write the Bounceprogressbar class as follows:

public class Bounceprogressbar extends View {//...}

Now you can use our Bounceprogressbar in the layout, it is important to note that we need to add the following code to the second line of the namespace to use our properties, you can also put it in the root element of the attribute.

        <org.roc.bounceprogressbar.bounceprogressbar            xmlns:bpb= "Http://schemas.android.com/apk/res-auto"            Android:layout_width= "Wrap_content"            android:layout_height= "wrap_content"            android:layout_ Centerhorizontal= "true"            android:layout_centervertical= "true"            bpb:shape= "Circle"            bpb:singlesrcsize= "8DP"            bpb:speed= "bpb:src="            #6495ED "/>

Customizing properties finally what we have to do is to get it in the code, where to get it, of course, is the Bounceprogressbar class of the construction method, the relevant code is as follows:

public Bounceprogressbar (Context context) {This (context, NULL, 0);} Public Bounceprogressbar (context context, AttributeSet Attrs) {This (context, attrs, 0);} Public Bounceprogressbar (context context, AttributeSet attrs, int defstyleattr) {Super (context, attrs, defstyleattr); Init (attrs);} private void init (AttributeSet attrs) {if (null = = Attrs) {return;} TypedArray a = GetContext (). Obtainstyledattributes (Attrs, r.styleable.bounceprogressbar); speed = A.getint ( r.styleable.bounceprogressbar_speed); size = A.getdimensionpixelsize (r.styleable.bounceprogressbar_ Singlesrcsize, shape = a.getint (r.styleable.bounceprogressbar_shape, 0); src = a.getdrawable ( R.STYLEABLE.BOUNCEPROGRESSBAR_SRC); A.recycle ();} 

Get the property or relatively simple, remember to recycle Typedarray. The first is to get the typedarray that we defined, and then a Get property value that is a one. Then maybe someone to say, I clearly did not define r.styleable.bounceprogressbar_xxx these things ah, in fact, this is the android automatically give We generate the declare-styleable in the Typedarray of each property in the index corresponding position, you can not find similar r.styleable.speed such things exist, it is how to correspond to it, click to see the R file to know, The value of R.styleable.bounceprogressbar_speed is 1 because speed is the 2nd attribute (0,1.), so you can be sure that the position of the property is directly written A.getint (1, 250) is also possible. The second parameter is a default value.

Shape of a graphic

After we get the value of the property, we can do the corresponding processing, here is the drawing shape of the acquisition, using the shape,src and size properties, speed and size will be mentioned in the next point.

First, we observed that three images are somewhat gradual, and I'm simply doing the transparency process, which is a transparent one at a time, and the effect can be better handled and then optimized. The image resources obtained from SRC are drawable, whether colordrawable or bitmapdrawable. We need to convert it to size bitmap, and then use canvas to crop it in shape. As for why the first turn bitmap, this is my practice, and then read the following after the operation if there is a better way to communicate.

/** * DRAWABLE→BITMAP (the size is "size") */private Bitmap Drawable2bitmap (drawable drawable) {Bitmap Bitmap = bitmap.cr Eatebitmap (size, size, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas (bitmap);d rawable.setbounds (0, 0, size, size);d Rawable.draw (canvas); return bitmap;}

Bitmap got, the shape we can operate, we first said Circle Circle, Diamond Rhombus, pentagram Pentagon, and then heart-shaped heart, because the processing method is somewhat different. Like other Shapeimageview I see as if I like to work with SVG and look at their code, like this: Https://github.com/siyamed/android-shape-imageview seems a little troubled, In contrast, my handling is relatively straightforward.


Circle Circle, Diamond Rhombus, pentagram Pentagon

These shapes can all be obtained using shapedrawable. We need the Bitmapshader renderer, which is required for the shapedrawable paint brush, and requires an empty bitmap bitmap, then a Canvas. As follows:

Bitmapshader Bitmapshader = new Bitmapshader (Srcbitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); Bitmap Bitmap = bitmap.createbitmap (size, size, Bitmap.Config.ARGB_8888); Canvas canvas = new canvas (bitmap); Path path; Shapedrawable shapedrawable = new shapedrawable (); Shapedrawable.getpaint (). Setantialias (True); Shapedrawable.getpaint (). Setshader (Bitmapshader); shapedrawable.setbounds (0, 0, size, size); Shapedrawable.setalpha (Alpha);

Canvas is the canvas on the shapedrawable, Bitmapshader is the renderer for shapedrawable brush paint, used to render processing graphics (bitmap converted from src drawable), The render mode chooses clamp, meaning that if the renderer goes beyond the original boundary range, it replicates the range's inner edge staining.

Round, we can directly use the ready-made:

Shapedrawable.setshape (New OvalShape ());

This shapedrawable is drawn out of the circle, of course, to call Shapedrawable.draw (canvas), the method, so that the bitmap will become a circular srcbitmap (method passed in the parameters), this method of the complete code is given below.

Diamond, we are like this:

Path = new Path ();p Ath.moveto (SIZE/2, 0);p ath.lineto (0, SIZE/2);p Ath.lineto (SIZE/2, size);p ath.lineto (size, SIZE/2 );p ath.close (); Shapedrawable.setshape (new Pathshape (path, size, size));

is the side length of the square of size, take the midpoint of each side, four points connected to it. We know that Android coordinates are generally the top left corner of the screen vertex is the origin of the coordinates, sitting punctuation found we connect the path is close. So the Pathshape is a diamond. Polygons can be drawn almost like this, the following five-angle shape is the same. Description: All graphics are drawn in a square with a length of size in the side.


The principle of the Pentagon is also used pathshape, but it needs a bit more coordinate points ah, need to carefully calculate the slowly debugging.

Path = new path ();//The Angle of the pentagramfloat radian = (float) (Math.PI * 36/180); float radius = size/2;//in t  He middle of the radius of the pentagonfloat radius_in = (float) (RADIUS * Math.sin (RADIAN/2)/Math.Cos (Radian));//The Starting point of the Polygonpath.moveto ((float) (RADIUS * Math.Cos (RADIAN/2)), 0);p Ath.lineto ((float) (RADIUS * math.c OS (RADIAN/2) + radius_in * Math.sin (Radian)), (float) (Radius-radius * Math.sin (RADIAN/2)));p Ath.lineto ((float) (Radi US * MATH.COS (RADIAN/2) * 2), (float) (Radius-radius * Math.sin (RADIAN/2)));p Ath.lineto ((float) (RADIUS * Math.Cos (RA DIAN/2) + radius_in * Math.Cos (RADIAN/2)), (float) (RADIUS + radius_in * Math.sin (RADIAN/2)));p Ath.lineto ((float) (RA  Dius * Math.Cos (RADIAN/2) + radius * Math.sin (Radian)), (float) (radius + radius * Math.Cos (radian)));p Ath.lineto ((float) (RADIUS * Math.Cos (RADIAN/2)), (float) (radius + radius_in));p Ath.lineto ((float) (RADIUS * Math.Cos (RADIAN/2)-Radiu S * Math.sin (Radian)), (fLoat) (Radius + radius * Math.Cos (radian)));p Ath.lineto ((float) (RADIUS * Math.Cos (RADIAN/2)-radius_in * Math.Cos (Radi AN/2)), (float) (RADIUS + radius_in * Math.sin (RADIAN/2)));p Ath.lineto (0, (float) (Radius-radius * Math.sin (Radian/ 2)));p Ath.lineto ((float) (RADIUS * Math.Cos (RADIAN/2)-radius_in * Math.sin (Radian)), (float) (Radius-radius * math.si N (RADIAN/2)));p ath.close ();//make these points closed Polygonsshapedrawable.setshape (new Pathshape (path, size, size) ;

There's a lot of wiring. Here the drawing of the five-angle shape is based on the angle of the specified five-angle radius, and then determine the connection starting point, and then the next point ... Finally closed, accidentally do not know where to go to.

Heart-shaped Heart

Path to draw the heart shape can not even achieve a straight line, the beginning is to use the path of the Quadto (x1, y1, x2, y2) method to draw the Bezier curve to achieve, found that the shape of the picture is not full, more like a cone (brain tonic), so give up this way. Then found this about the heart-shaped introduction heart Curve, and then adopted his fourth method (such as), that is, the use of two oval shape to cut the implementation.



1. Draw an oval shape

</pre><pre name= "code" class= "Java" >
</pre><pre name= "code" class= "java" >   //canvas bitmap bitmapshader, etc., the above code already has   Path = new Path ();   Paint paint = new paint ();   Paint.setantialias (true);   Paint.setshader (Bitmapshader);   Matrix matrix = new Matrix (); Control rotates   Region regions = new Area ();//crop a section of graphics   RECTF ovalrect = new RECTF (SIZE/4, 0, size-(SIZE/4), size); 
   path.addoval (Ovalrect, Path.Direction.CW);

</pre></p><p></p>< P></p>2, rotate the figure, about 45 degrees <p><pre name= "code" class= "Java" >matrix.postrotate (SIZE/2 and SIZE/2); Path.transform (matrix, path);



3, select the right half of the shape of the rotation, and use Cancas to draw this half of the heart shape

Path.transform (matrix, path); Region.setpath (Path, new region ((int) SIZE/2, 0, (int) size, (int) size); Canvas.drawpath ( Region.getboundarypath (), paint);



4, repeat 1, 2, 3 simultaneously change the direction angle and the clipping area

Matrix.reset ();p ath.reset ();p ath.addoval (Ovalrect, Path.Direction.CW); Matrix.postrotate ( -42, SIZE/2, SIZE/2); Path.transform (matrix, path); Region.setpath (Path, new region (0, 0, (int) SIZE/2, (int) size); Canvas.drawpath ( Region.getboundarypath (), paint);

So we finished the heart-shaped picture of the cutting work, the resulting bitmap become heart-shaped:

This heart can meet people.
The next step is to finish the drawing of your heart.



Drawing of view

When it comes to the drawing process of view, the following trilogy is needed:

  1. Draw--ondraw (): How to draw this view.


    Measurement

    The measurement of the Bounceprogressbar control is relatively simple, when the wrap_content height and width are 5 times times and 4 times times the size, in other cases, the specified width of height for the specific measured value is good. Then determine the horizontal position of the three graphs in the control:

    @Overrideprotected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (Widthmeasurespec, HEIGHTMEASURESPEC); int sizewidth = Measurespec.getsize (widthmeasurespec); int sizeheight = Measurespec.getsize ( HEIGHTMEASURESPEC); int modewidth = Measurespec.getmode (widthmeasurespec); int modeheight = Measurespec.getmode ( Heightmeasurespec) setmeasureddimension ((modewidth = = measurespec.exactly)? mwidth = Sizewidth:mwidth, (modeHeight = = measurespec.exactly)? Mheight = sizeheight:mheight); firstdx = MWIDTH/4-size/2;//horizontal position of first graphic SECONDDX = MWIDTH/2-SIZE/2;//...THIRDDX = 3 * MWIDTH/4-size/2;//...}
    Mwidth and Mheight are also set to the measured sizewidth and sizeheight when there is a width height that specifies a specific value.

    Layout

    When it comes to layout, the first thing to be clear is that the beat of the image is controlled by property animation, what is property animation? Let me say one thing: You can change a property of an object in the form of an animated effect. You can look for information before you know it.

    The layout here determines the operation of the various positions in the view, which is generally not used as a single control, where I initialize the animation and begin the operation. You can see that our Bounceprogressbar is three graphics in the beating.

    The three attributes are encapsulated as follows:

    /** * firstbitmaptop ' s property. The change of the height through canvas is * onDraw () method. */private Property<bounceprogressbar, integer> firstbitmaptopproperty = new Property<bounceprogressbar, Integer> (Integer.class, "Firstdrawabletop") {@Overridepublic Integer get (Bounceprogressbar obj) {return Obj.firstbitmaptop;} public void Set (Bounceprogressbar obj, Integer value) {obj.firstbitmaptop = Value;invalidate ();};};/ * * secondbitmaptop ' s property. The change of the height through canvas is * onDraw () method. */private Property<bounceprogressbar, integer> secondbitmaptopproperty = new Property<bounceprogressbar, Integer> (Integer.class, "Seconddrawabletop") {@Overridepublic Integer get (Bounceprogressbar obj) {return Obj.secondbitmaptop;} public void Set (Bounceprogressbar obj, Integer value) {obj.secondbitmaptop = Value;invalidate ();};};/ * * thirdbitmaptop ' s property. The change of the height through canvas is * onDraw () method. */private Property<bounceprogRessbar, integer> thirdbitmaptopproperty = new Property<bounceprogressbar, integer> (Integer.class, " Thirddrawabletop ") {@Overridepublic Integer get (Bounceprogressbar obj) {return obj.thirdbitmaptop;} public void Set (Bounceprogressbar obj, Integer value) {obj.thirdbitmaptop = Value;invalidate ();};};
    onlayout section is as follows:
    @Overrideprotected void OnLayout (Boolean changed, int left, int top, int. right, int. bottom) {super.onlayout (changed, left, Top, right, bottom), if (bouncer = = NULL | |!bouncer.isrunning ()) {Objectanimator firstanimator = Initdrawableanimator (fir Stbitmaptopproperty, speed, size/2,mheight-size); Objectanimator secondanimator = Initdrawableanimator ( Secondbitmaptopproperty, speed, size/2,mheight-size); Secondanimator.setstartdelay (+); objectanimator Thirdanimator = Initdrawableanimator (Thirdbitmaptopproperty, speed, size/2,mheight-size); Thirdanimator.setstartdelay (Bouncer) = new Animatorset (); Bouncer.playtogether (Firstanimator, SecondAnimator, Thirdanimator); Bouncer.start ();}} Private Objectanimator Initdrawableanimator (Property<bounceprogressbar, integer> property, int duration,int Startvalue, int endvalue) {Objectanimator animator = Objectanimator.ofint (this, property, Startvalue, Endvalue); Animator.setduration (duration); Animator.setrepeatcount (animation.infinite); animAtor.setrepeatmode (Valueanimator.reverse); Animator.setinterpolator (new Accelerateinterpolator ()); return animator ;}
    The value transformation of an animation is from size to mheight-size, and the reason for subtracting size is that the size range of the view itself is greater than (Mheight, mheight) on the left side of the canvas.


    Draw

    The work done here is not much, it is based on the horizontal position of each image, and the height controlled by the property animation to come and go to draw bitmap on the canvas.

    @Overrideprotected synchronized void OnDraw (canvas canvas) {/* Draw three bitmap */firstbitmapmatrix.reset (); Firstbitmapmatrix.posttranslate (FIRSTDX, firstbitmaptop); Secondbitmapmatrix.reset (); Secondbitmapmatrix.settranslate (SECONDDX, secondbitmaptop); Thirdbitmapmatrix.reset (); Thirdbitmapmatrix.settranslate (THIRDDX, thirdbitmaptop); Canvas.drawbitmap (Firstbitmap, FirstBitmapMatrix, MPaint) ; Canvas.drawbitmap (Secondbitmap, Secondbitmapmatrix, Mpaint); Canvas.drawbitmap (Thirdbitmap, ThirdBitmapMatrix, Mpaint);}
    The position is controlled by the matrix, because the deformation of the ground was also taken into account, but now it is removed first.

    The overall drawing process is through property animation to control the position of each image on the canvas, call the Invalidate () method when the property changes to notify the redraw line, it looks like the effect of the beating, the speed of the change is to set the animation interpolation to complete.

Android Custom View Bounceprogressbar

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.