Android--Custom View Implementation Keep Welcome page Countdown Effect

Source: Internet
Author: User
Tags drawtext getcolor

1, recently opened keep app, found its welcome page Countdown effect is also good, so intend to write their own, and then have this article.

2, Let's take a look at the effect we've achieved today.

Compared to our usual countdown, the effect of this implementation is more of the outside ring, which is the interesting point of our custom view.

Know the effect we first come to the effect analysis of a wave, first of all, a countdown effect, the time when the arc is constantly reduced, the text is constantly changing, the visual change is roughly the two parts, but in fact our UI is composed of three parts: The inside of the solid circle, the outside of the arc, the text inside. Knowing the composition of our UI, we're going to open the roll.

Before we start, let's review our basic process of simple custom view

/** * Customize view in several steps * 1, customize View properties * 2, get our custom properties in view * 3, rewrite onmeasure * 4, rewrite OnDraw * 5, rewrite onlayout (this determines where the view is placed) */

 ①, defining custom properties

We based on the above basic steps, we know first of all we based on the first to determine our custom properties, here I briefly analyzed, the main added eight custom properties, namely the radius and color of the solid circle inside, the color and radius of the arc, the size and color of the text inside, the length of the total countdown time, The direction of the arc reduction (divided into clockwise and counterclockwise), so first create the Attrs.xml file in the Res/values directory, add the following properties: (here if you have a custom attribute is not familiar with the students can go to understand I have written this article, can be more profound understanding)

<?xml version= "1.0" encoding= "Utf-8"?><resources> <declare-styleable    name= "Circletimerview" >        <attr name= "Solid_circle_radius" format= "Dimension"/>        <attr name= "solid_circle_color" format = "Color"/>        <attr name= "empty_circle_color" format= "color"/> <attr name=        "Empty_circle_radius" format= "Dimension"/>        <attr name= "circle_text_size" format= "Dimension"/>        <attr name= "Circle_ Text_color "format=" color "/>        <attr name=" circle_draw_orientation "format=" enum ">            <!--clockwise-- >            <enum name= "Clockwise" value= "1"/>            <!--counterclockwise--<enum name=            "anticlockwise" value= " 2 "/>        </attr>        <attr name=" time_length "format=" integer "/>    </declare-styleable ></resources>

 ②, get custom properties, initialize some properties

first create Circletimerview class, inherit from view class

public class Circletimerview extends View {private context context;    Inside solid circle Color private int msolidcirclecolor;    Inside circle radius private int Msolidcircleradius;    The color of the outer arc is private int memptycirclecolor;    The radius of the outer arc (which can be achieved using the width of the brush) private int memptycircleradius;    Text size private int mtextsize;    Text color private int mtextcolor;    Text private String MText;    Draw the direction private int mdraworientation;    The speed of Arc drawing private int mspeed;    Round brush private paint mpaintcircle;    The brush of the arc private paint mpaintarc;    Draw the brush of the text private Paint mpainttext;    Duration private int mtimelength;    Default value private int defaultsolidcirclecolor;    private int defaultemptycirclecolor;    private int Defaultsolidcircleradius;    private int Defaultemptycircleradius;    private int defaulttextcolor;    private int defaulttextsize;    private int defaulttimelength;    private int defaultdraworitation;    The angle of the current fan is private int startprogress; Private INT Endprogress;    private float currprogress;    Animation set private Animatorset set;    Callback Private Oncountdownfinish Oncountdownfinish;    Public Circletimerview (Context context) {this (context,null);    } public Circletimerview (context context, @Nullable AttributeSet attrs) {This (context, attrs,0); } public Circletimerview (context context, @Nullable attributeset attrs, int defstyleattr) {Super (context, attrs        , defstyleattr);        This.context = context;        Initialize default value Defaultsolidcirclecolor = Getresources (). GetColor (R.color.colorprimary);        Defaultemptycirclecolor = Getresources (). GetColor (r.color.coloraccent);        Defaulttextcolor = Getresources (). GetColor (R.color.coloryellow);        Defaultsolidcircleradius = (int) getresources (). Getdimension (R.DIMEN.DIMEN_20);        Defaultemptycircleradius = (int) getresources (). Getdimension (R.DIMEN.DIMEN_25); defaulttextsize = (int) getresources (). Getdimension (R.DIMEN.DIMEN_16);        Defaulttimelength = 3;        Defaultdraworitation = 1;        Gets the custom attribute TypedArray a = context.obtainstyledattributes (Attrs, R.styleable.circletimerview);        Msolidcirclecolor = A.getcolor (R.styleable.circletimerview_solid_circle_color,defaultsolidcirclecolor); Msolidcircleradius = A.getdimensionpixeloffset (R.styleable.circletimerview_solid_circle_radius,        Defaultsolidcircleradius);        Memptycirclecolor = A.getcolor (R.styleable.circletimerview_empty_circle_color,defaultemptycirclecolor); Memptycircleradius = A.getdimensionpixeloffset (R.styleable.circletimerview_empty_circle_radius,        Defaultemptycircleradius);        Mtextcolor = A.getcolor (R.styleable.circletimerview_circle_text_color,defaulttextcolor);        Mtextsize = A.getdimensionpixeloffset (r.styleable.circletimerview_circle_text_size, defaultTextSize);        Mdraworientation = A.getint (r.styleable.circletimerview_circle_draw_orientation,defaultdraworitation); Mtimelength = A.getint (R.styleable.circletimerview_time_length, defaulttimelength);        A.recycle ();    Init ();        } private void Init () {//initialization brush mpaintcircle = new paint ();        Mpaintcircle.setstyle (Paint.Style.FILL);        Mpaintcircle.setantialias (TRUE);        Mpaintcircle.setcolor (Msolidcirclecolor);        Mpaintarc = new Paint ();        Mpaintarc.setstyle (Paint.Style.STROKE);        Mpaintarc.setantialias (TRUE);        Mpaintarc.setcolor (Memptycirclecolor);        Mpaintarc.setstrokewidth (Memptycircleradius-msolidcircleradius);        Mpainttext = new Paint ();        Mpainttext.setstyle (Paint.Style.STROKE);        Mpainttext.setantialias (TRUE);        Mpainttext.settextsize (mtextsize);        Mpainttext.setcolor (Mtextcolor);        mtext= mtimelength + "";            if (defaultdraworitation = = 1) {startprogress = 360;        endprogress = 0;            }else {startprogress = 0;        endprogress = 360; } currprogress = StartprogrESS; }

 Here I initialize some default values in the constructor, then get the custom properties, and then initialize three brushes, representing: solid circle, ARC, Text brush (this very good understanding), and then according to the clockwise and counterclockwise to initialize the starting angle and end angle, very simple is not too much nonsense.

③, overriding Onmeasure methods

Here because our effect is very simple, basically is a square, so here I am with the radius of the outside arc when the view of the wide, not to Judge Match_parent, Wrap_content, such as the case, the code is as follows:

@Override    protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {        super.onmeasure ( Widthmeasurespec, Heightmeasurespec);        Set the width height        setmeasureddimension (memptycircleradius*2,memptycircleradius*2);    }

  ④, overriding the OnDraw method

This is also our custom view key, first we draw arc and text is very simple, draw arc words may some classmates have not contacted, here I previously wrote an article, we can go to see, we here to use the knowledge points are the same, so no nonsense

  

@Override    protected void OnDraw (canvas canvas) {        super.ondraw (canvas);        Draw Background Circle        canvas.drawcircle (memptycircleradius,memptycircleradius,msolidcircleradius,mpaintcircle);        Draw Arc        RECTF oval = new RECTF ((Memptycircleradius-msolidcircleradius)/2, (Memptycircleradius-msolidcircleradius )/2                , Memptycircleradius + (Memptycircleradius-msolidcircleradius)/2+msolidcircleradius, MEmptyCircleRadius + ( Memptycircleradius-msolidcircleradius)/2+msolidcircleradius); Defines the bounds of the shape and size of the arc        Canvas.drawarc (Oval, -90, currprogress, False, MPAINTARC);//Draw arcs based on progress/        /Draw text        Rect Mbound = new Rect ();        Mpainttext.gettextbounds (mText, 0, Mtext.length (), mbound);        Canvas.drawtext (MText, getwidth ()/2-mbound.width ()/2, GetHeight ()/2 + mbound.height ()/2, mpainttext);    }

 At this time, we can look at our custom view effect, will we currprogress first write dead 270, to see our effect, here is a note in the use of our custom properties, remember to add our custom space in the layout file. The results are as follows:

  Can see here our effect basically tried out, the key is how to make it move, here our first reaction is handle or timer to achieve a countdown, at first, the brother also use a timer to achieve, However, because the UI changes are two different rate of view in the change: the continuous reduction of the arc, TextView font gradually smaller, so here use a timer can not be implemented, with two, if using two is not a software engineering, so here is intended to use animation to achieve, The specific code is as follows:

/** * Control via external switch */public void start () {Valueanimator Animator1 = valueanimator.offloat (startprogr        ess,endprogress);        Animator1.setinterpolator (New Linearinterpolator ()); Animator1.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Override public void Onani                Mationupdate (Valueanimator valueanimator) {currprogress = (float) valueanimator.getanimatedvalue ();            Invalidate ();        }        });        Valueanimator Animator2 = Valueanimator.ofint (mtimelength,0);        Animator2.setinterpolator (New Linearinterpolator ()); Animator2.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Override public void Onani                Mationupdate (Valueanimator valueanimator) {mtimelength = (int) valueanimator.getanimatedvalue ();                if (Mtimelength = = 0) return;            MText =mtimelength+ "";     }        });   set = new Animatorset ();        Set.playtogether (ANIMATOR1,ANIMATOR2);        Set.setduration (mtimelength * 1000);        Set.start (); Set.addlistener (New Animator.animatorlistener () {@Override public void Onanimationstart (Animator an Imator) {} @Override public void Onanimationend (Animator Animator) {if (                Oncountdownfinish = null) {oncountdownfinish.onfinish ();            }} @Override public void Onanimationcancel (Animator Animator) {}    @Override public void Onanimationrepeat (Animator Animator) {}}); }

very simple, is two valueanimator, listen to the change of the value, and then the final completion of the animation using the interface callback, Notifies the host to complete the TODO operation, so here we basically fully implement the customization of our view, the complete code for Circletimerview is as follows:

Package Com.ysten.circletimerdown.view;import Android.animation.animator;import Android.animation.AnimatorSet; Import Android.animation.valueanimator;import Android.content.context;import Android.content.res.TypedArray; Import Android.graphics.canvas;import Android.graphics.paint;import Android.graphics.rect;import Android.graphics.rectf;import Android.support.annotation.nullable;import Android.util.attributeset;import Android.view.view;import Android.view.animation.animationset;import Android.view.animation.LinearInterpolator; Import Com.ysten.circletimerdown.r;import java.util.timer;import java.util.timertask;/** * Author:wangjitao * e-mail: [email protected] * TIME:2017/08/14 * desc: * version:1.0 */public class Circletimerview extends View {PR    Ivate context Context;    Inside solid circle Color private int msolidcirclecolor;    Inside circle radius private int Msolidcircleradius;    The color of the outer arc is private int memptycirclecolor; Radius of the outer arc (can be achieved using the width of the brush) private int Memptycircleradius;    Text size private int mtextsize;    Text color private int mtextcolor;    Text private String MText;    Draw the direction private int mdraworientation;    The speed of Arc drawing private int mspeed;    Round brush private paint mpaintcircle;    The brush of the arc private paint mpaintarc;    Draw the brush of the text private Paint mpainttext;    Duration private int mtimelength;    Default value private int defaultsolidcirclecolor;    private int defaultemptycirclecolor;    private int Defaultsolidcircleradius;    private int Defaultemptycircleradius;    private int defaulttextcolor;    private int defaulttextsize;    private int defaulttimelength;    private int defaultdraworitation;    The angle of the current fan is private int startprogress;    private int endprogress;    private float currprogress;    Animation set private Animatorset set;    Callback Private Oncountdownfinish Oncountdownfinish;    Public Circletimerview (Context context) {this (context,null); } public Circletimerview (context context, @NullableAttributeSet attrs) {This (context, attrs,0); } public Circletimerview (context context, @Nullable attributeset attrs, int defstyleattr) {Super (context, attrs        , defstyleattr);        This.context = context;        Initialize default value Defaultsolidcirclecolor = Getresources (). GetColor (R.color.colorprimary);        Defaultemptycirclecolor = Getresources (). GetColor (r.color.coloraccent);        Defaulttextcolor = Getresources (). GetColor (R.color.coloryellow);        Defaultsolidcircleradius = (int) getresources (). Getdimension (R.DIMEN.DIMEN_20);        Defaultemptycircleradius = (int) getresources (). Getdimension (R.DIMEN.DIMEN_25);        defaulttextsize = (int) getresources (). Getdimension (R.DIMEN.DIMEN_16);        Defaulttimelength = 3;        Defaultdraworitation = 1;        Gets the custom attribute TypedArray a = context.obtainstyledattributes (Attrs, R.styleable.circletimerview); Msolidcirclecolor = A.getcolor (R.STYLEABLE.CIRCLETIMERVIEW_SOLID_CIRCLE_COLOR,DEFAULTSOLIDCIRCLEColor); Msolidcircleradius = A.getdimensionpixeloffset (R.styleable.circletimerview_solid_circle_radius,        Defaultsolidcircleradius);        Memptycirclecolor = A.getcolor (R.styleable.circletimerview_empty_circle_color,defaultemptycirclecolor); Memptycircleradius = A.getdimensionpixeloffset (R.styleable.circletimerview_empty_circle_radius,        Defaultemptycircleradius);        Mtextcolor = A.getcolor (R.styleable.circletimerview_circle_text_color,defaulttextcolor);        Mtextsize = A.getdimensionpixeloffset (r.styleable.circletimerview_circle_text_size, defaultTextSize);        Mdraworientation = A.getint (r.styleable.circletimerview_circle_draw_orientation,defaultdraworitation);        Mtimelength = A.getint (R.styleable.circletimerview_time_length, defaulttimelength);        A.recycle ();    Init ();        } private void Init () {//initialization brush mpaintcircle = new paint ();        Mpaintcircle.setstyle (Paint.Style.FILL);        Mpaintcircle.setantialias (TRUE); MpaiNtcircle.setcolor (Msolidcirclecolor);        Mpaintarc = new Paint ();        Mpaintarc.setstyle (Paint.Style.STROKE);        Mpaintarc.setantialias (TRUE);        Mpaintarc.setcolor (Memptycirclecolor);        Mpaintarc.setstrokewidth (Memptycircleradius-msolidcircleradius);        Mpainttext = new Paint ();        Mpainttext.setstyle (Paint.Style.STROKE);        Mpainttext.setantialias (TRUE);        Mpainttext.settextsize (mtextsize);        Mpainttext.setcolor (Mtextcolor);        mtext= mtimelength + "";            if (defaultdraworitation = = 1) {startprogress = 360;        endprogress = 0;            }else {startprogress = 0;        endprogress = 360;    } currprogress = startprogress; } @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (widthmeas        Urespec, Heightmeasurespec);    Set wide height setmeasureddimension (memptycircleradius*2,memptycircleradius*2); } @Override Protected void OnDraw (canvas canvas) {super.ondraw (canvas);        Draw Background Circle Canvas.drawcircle (memptycircleradius,memptycircleradius,msolidcircleradius,mpaintcircle); Draw arc RECTF oval = new RECTF ((Memptycircleradius-msolidcircleradius)/2, (Memptycircleradius-msolidcircleradius )/2, Memptycircleradius + (Memptycircleradius-msolidcircleradius)/2+msolidcircleradius, MEmptyCircleRadi US + (Memptycircleradius-msolidcircleradius)/2+msolidcircleradius); Defines the bounds of the shape and size of the arc Canvas.drawarc (Oval, -90, currprogress, False, Mpaintarc);        Draw arc//Draw text based on progress rect mbound = new rect ();        Mpainttext.gettextbounds (mText, 0, Mtext.length (), mbound);    Canvas.drawtext (MText, getwidth ()/2-mbound.width ()/2, GetHeight ()/2 + mbound.height ()/2, mpainttext);    } public Oncountdownfinish Getoncountdownfinish () {return oncountdownfinish;       } public void Setoncountdownfinish (Oncountdownfinish oncountdownfinish) { This.oncountdownfinish = Oncountdownfinish; }/** * Control via external switch */public void start () {Valueanimator Animator1 = valueanimator.offloat (startprogres        s,endprogress);        Animator1.setinterpolator (New Linearinterpolator ()); Animator1.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Override public void Onani                Mationupdate (Valueanimator valueanimator) {currprogress = (float) valueanimator.getanimatedvalue ();            Invalidate ();        }        });        Valueanimator Animator2 = Valueanimator.ofint (mtimelength,0);        Animator2.setinterpolator (New Linearinterpolator ()); Animator2.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Override public void Onani                Mationupdate (Valueanimator valueanimator) {mtimelength = (int) valueanimator.getanimatedvalue ();                if (Mtimelength = = 0) return; MText=mtimelength+ "";        }        });        set = new Animatorset ();        Set.playtogether (ANIMATOR1,ANIMATOR2);        Set.setduration (mtimelength * 1000);        Set.start (); Set.addlistener (New Animator.animatorlistener () {@Override public void Onanimationstart (Animator an Imator) {} @Override public void Onanimationend (Animator Animator) {if (                Oncountdownfinish = null) {oncountdownfinish.onfinish ();            }} @Override public void Onanimationcancel (Animator Animator) {}    @Override public void Onanimationrepeat (Animator Animator) {}});    } public void Cancelanim () {if (set! = null) set.pause ();    } public interface oncountdownfinish{void OnFinish (); }}

 The result of the final implementation is as follows:

GitHub code address, the need for the source of the students can go to download.

Android--Custom View Implementation Keep Welcome page Countdown Effect

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.