Android implements cool checkbox effect _android

Source: Internet
Author: User
Tags border color getcolor int size min pow

First, put out the implementation of the effect of the diagram:

GIF may be a bit too fast to run on a real machine better. Our main idea is to use attribute animation to dynamically draw the selected state and the drawing process of the hook. See the above effect picture, I believe we can not wait to be tempted, then let us start.

Customize the first step of view: Custom properties.

<?xml version= "1.0" encoding= "Utf-8"?>
<resources>
 <declare-styleable name= "Smoothcheckbox ">
 <!--animation duration-->
 <attr name=" duration "format=" integer "></attr>
 <!--border Width-- >
 <attr name= "strikewidth" format= "dimension|reference" ></attr>
 <!--border color-->
 <attr name= "bordercolor" format= "color|reference" ></attr>
 <!--the color of the selected state-->
 <attr name = "Trimcolor" format= "color|reference" ></attr>
 <!--to tick color-->
 <attr name= "Tickcolor" format= "Color|reference" ></attr>
 <!--hook width--> <attr name= "Tickwidth"
 Dimension|reference "></attr>
 </declare-styleable>
</resources>

We named the checkbox Smoothcheckbox, defined a few, and so on, to use the attributes. This step is very simple, I believe we are proficient.

Next look at onmeasure (int widthmeasurespec, int heightmeasurespec):

@Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (Widthmeasurespec, Hei
 GHTMEASURESPEC);
 int widthsize = measurespec.getsize (Widthmeasurespec);
 int widthmode = Measurespec.getmode (Widthmeasurespec);
 if (Widthmode = = measurespec.exactly) {mwidth = widthsize;
 else {mwidth = 40;
 int heightsize = measurespec.getsize (Heightmeasurespec);
 int heightmode = Measurespec.getmode (Heightmeasurespec);
 if (Heightmode = = measurespec.exactly) {mheight = heightsize;
 else {mheight = 40;
 } setmeasureddimension (Mwidth, mheight);
 int size = Math.min (Mwidth, mheight);
 Center = SIZE/2;
 Mradius = (int) ((size-mstrokewidth)/2/1.2f);
 Startpoint.set (center * 14/30, center * 28/30);
 Breakpoint.set (center * 26/30, center * 40/30);

 Endpoint.set (center * 44/30, center * 20/30);
 Downlength = (float) math.sqrt (Math.pow (startpoint.x-breakpoint.x, 2f) + MATH.POW (STARTPOINT.Y-BREAKPOINT.Y, 2f)); Uplength = (FloaT) math.sqrt (MATH.POW (endpoint.x-breakpoint.x, 2f) + MATH.POW (ENDPOINT.Y-BREAKPOINT.Y, 2f));
Totallength = Downlength + uplength; }

At first it measured the width and height of the Smoothcheckbox, and the default width of the height was defined in a casual way, and of course you can modify and refine it yourself. Then it is to set the radius and so on, the final startpoint, breakpoint, endpoint respectively corresponding to check the tick three points (as for why these few numbers, that is the empirical value); Downlength is the distance between StartPoint and breakpoint, and the corresponding uplength is the distance between breakpoint and endpoint. This is the following illustration:

Before looking at OnDraw (Canvas Canvas), let's take a look at the two sets of animations, which are the animations in the selected state and the unselected animations:

The animated private void Checkedanimation () {Animatedvalue = 0f is not checked to the selected animation;
 Tickvalue = 0f;
 Animated mvalueanimator = Valueanimator.offloat (0f, 1.2f, 1f) when selected. Setduration (2 * DURATION/5);
 Mvalueanimator.setinterpolator (New Acceleratedecelerateinterpolator ());
 The Animated Mtickvalueanimator = Valueanimator.offloat (0f, 1f). Setduration (3 * DURATION/5);
 Mtickvalueanimator.setinterpolator (New Linearinterpolator ()); Mtickvalueanimator.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Override public void
   Onanimationupdate (Valueanimator valueanimator) {//Get animation execution Progress Tickvalue = (float) valueanimator.getanimatedvalue ();
  Postinvalidate ();
 }
 }); Mvalueanimator.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Override public void 
   Onanimationupdate (Valueanimator valueanimator) {//Get animation execution Progress Animatedvalue = (float) valueanimator.getanimatedvalue ();
  Postinvalidate ();
 }
 }); Mvalueanimator.addlistener (New Animatorlisteneradapter () {@Override public void Onanimationend (animator animation) {//When the background of the animation is completed and then start to tick the animation Mtickvalueanimator.start ();
 LOG.I (TAG, "Mtickvalueanimator.start ();");
Mvalueanimator.start ();
 ///from selected to unchecked animation private void Uncheckedanimation () {animatedvalue = 0f;
 Mvalueanimator = Valueanimator.offloat (1f, 0f). Setduration (2 * DURATION/5);
 Mvalueanimator.setinterpolator (New Accelerateinterpolator ()); Mvalueanimator.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Override public void
   Onanimationupdate (Valueanimator valueanimator) {animatedvalue = (float) valueanimator.getanimatedvalue ();
  Postinvalidate ();
 }
 });
Mvalueanimator.start (); }

These two sets of animations are called when you click Smoothcheckbox. Similarly, it is the progress of animation execution in animation execution, and then call Postinvalidate (), let Smoothcheckbox redraw. After reading this is the ultimate big recruit OnDraw (Canvas Canvas):

@Override protected void OnDraw (Canvas Canvas) {Super.ondraw (Canvas);
 Canvas.save ();
 Drawborder (canvas);
 Drawtrim (canvas);
 if (ischecked) {Drawtick (canvas);
} canvas.restore ();
 ///Draw to hook private void Drawtick (Canvas Canvas) {//Get draw on hook progress Float temp = Tickvalue * TOTALLENGTH;
 LOG.I (TAG, "temp:" + temp + "Downlength:" + downlength); To determine if it is just the beginning of the tick, that is equal to StartPoint if (Float.compare (Tickvalue, 0f) = 0) {log.i (TAG, "startpoint:" + Startpoint.x + ",
  "+ Startpoint.y);
  Path.reset ();
 Path.moveto (Startpoint.x, STARTPOINT.Y); ///If the progress of the draw is over breakpoint, that is (Breakpoint,endpoint] if (temp > Downlength) {path.moveto (startpoint.x, StartPoint
  . y);
  Path.lineto (Breakpoint.x, BREAKPOINT.Y);
  LOG.I (TAG, "endPoint:" + endpoint.x + "," + endpoint.y); Path.lineto ((endpoint.x-breakpoint.x) * (temp-downlength)/Uplength + Breakpoint.x, (endpoint.y-breakpoint.y) * (Te
 Mp-downlength)/uplength + Breakpoint.y); The progress of the else {//Draw check is between startpoinit and breakpoint, i.e. (Startpoint,breakpoint] LOG.I (TAG, "Down x:" + (breakpoint.x-startpoint.x) * temp/downlength + ", down Y:" + (break
  POINT.Y-STARTPOINT.Y) * temp/downlength); Path.lineto ((breakpoint.x-startpoint.x) * temp/downlength + startpoint.x, (breakpoint.y-startpoint.y) * TEMP/DOWNL
 Ength + startpoint.y);
} canvas.drawpath (path, tickpaint);
 //Draw Border private void Drawborder (Canvas Canvas) {float temp;
 The animatedvalue lets the border produce a "overshooting" animation if (Animatedvalue > 1f) {temp = Animatedvalue * Mradius;
 else {temp = Mradius;
Canvas.drawcircle (center, center, temp, borderpaint); }//Draw checkbox internal private void Drawtrim (Canvas Canvas) {canvas.drawcircle (center, center, (mradius-mstrokewidth) * ani
Matedvalue, Trimpaint); }

OnDraw (Canvas Canvas) code in the logic is basically added annotation, the main principle is to understand the relatively simple. In the drawing of the check to distinguish between the current state of the draw on the hook, and then the corresponding processing to draw lines, the rest is simple. About Smoothcheckbox's explanation to here is almost.

The complete code for Smoothcheckbox is posted below:

public class Smoothcheckbox extends View implements View.onclicklistener {//Animation duration private long duration;
 Border width private float mstrokewidth;
 To hook width private float mtickwidth;
 Interior brushes private Paint trimpaint;
 Border brush private Paint borderpaint;
 To sketch pen private Paint tickpaint;
 Default border width private float defaultstrikewidth;
 Default to hook width private float defaulttickwidth;
 width private int mwidth;
 highly private int mheight;
 Border color private int bordercolor;
 Interior color private int trimcolor;
 to tick color private int tickcolor;
 Radius private int Mradius;
 Center point Private Int Center;
 Whether the private Boolean ischecked is selected;
 On the hook downward length private float downlength;
 The length of the hook upward private float uplength;
 The total length of the hook is private float totallength;

 Listener Private Oncheckedchangelistener listener;

 Private Valueanimator Mvalueanimator;

 Private Valueanimator Mtickvalueanimator;

 private float Animatedvalue;
 private float Tickvalue;
 To tick start dot private point startpoint = new points (); Right hookTurn private Point breakpoint = new points ();

 To tick end dot private point endPoint = new points ();

 private static final String TAG = "Smoothcheckbox";

 private static final String key_instance_state = "Instancestate";

 Private path PATH = new Path ();
 public void Setoncheckedchangelistener (Oncheckedchangelistener listener) {This.listener = listener;
 The public Smoothcheckbox {This (context, NULL);
 Public Smoothcheckbox (context, AttributeSet attrs) {This (context, attrs, 0);
  Public Smoothcheckbox (context, AttributeSet attrs, int defstyleattr) {Super (context, attrs, defstyleattr);
  TypedArray a = GetContext (). Obtainstyledattributes (Attrs, R.styleable.smoothcheckbox);

  Duration = A.getint (r.styleable.smoothcheckbox_duration, 600); Defaultstrikewidth = Typedvalue.applydimension (Typedvalue.complex_unit_dip, 1, Getresources (). GetDisplayMetrics ())
  ; Mstrokewidth = A.getdimension (R.styleable.smoothcheckbox_strikewidth, DefaultstrikewiDTH);
  Defaulttickwidth = Typedvalue.applydimension (Typedvalue.complex_unit_dip, 2, Getresources (). GetDisplayMetrics ());
  Mtickwidth = A.getdimension (R.styleable.smoothcheckbox_tickwidth, defaulttickwidth); BorderColor = A.getcolor (R.styleable.smoothcheckbox_bordercolor, Getresources (). GetColor (Android.
  R.color.darker_gray)); Trimcolor = A.getcolor (R.styleable.smoothcheckbox_trimcolor, Getresources (). GetColor (Android.
  R.color.holo_green_light)); Tickcolor = A.getcolor (R.styleable.smoothcheckbox_tickcolor, Getresources (). GetColor (Android.
  R.color.white));

  A.recycle ();
  Trimpaint = new Paint (Paint.anti_alias_flag);
  Trimpaint.setstyle (Paint.Style.FILL);

  Trimpaint.setcolor (Trimcolor);
  Borderpaint = new Paint (Paint.anti_alias_flag);
  Borderpaint.setstrokewidth (Mstrokewidth);
  Borderpaint.setcolor (bordercolor);

  Borderpaint.setstyle (Paint.Style.STROKE);
  Tickpaint = new Paint (Paint.anti_alias_flag);
  Tickpaint.setcolor (Tickcolor); Tickpaint.setstyle (Paint.Style.STROKE);
  Tickpaint.setstrokecap (Paint.Cap.ROUND);

  Tickpaint.setstrokewidth (Mtickwidth);
 Setonclicklistener (this);  @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (Widthmeasurespec,
  HEIGHTMEASURESPEC);
  int widthsize = measurespec.getsize (Widthmeasurespec);
  int widthmode = Measurespec.getmode (Widthmeasurespec);
  if (Widthmode = = measurespec.exactly) {mwidth = widthsize;
  else {mwidth = 40;
  int heightsize = measurespec.getsize (Heightmeasurespec);
  int heightmode = Measurespec.getmode (Heightmeasurespec);
  if (Heightmode = = measurespec.exactly) {mheight = heightsize;
  else {mheight = 40;
  } setmeasureddimension (Mwidth, mheight);
  int size = Math.min (Mwidth, mheight);
  Center = SIZE/2;
  Mradius = (int) ((size-mstrokewidth)/2/1.2f);
  Startpoint.set (center * 14/30, center * 28/30);
  Breakpoint.set (center * 26/30, center * 40/30); Endpoint.set (center * 44/30, center * 20/30);
  Downlength = (float) math.sqrt (Math.pow (startpoint.x-breakpoint.x, 2f) + MATH.POW (STARTPOINT.Y-BREAKPOINT.Y, 2f));
  Uplength = (float) math.sqrt (Math.pow (endpoint.x-breakpoint.x, 2f) + MATH.POW (ENDPOINT.Y-BREAKPOINT.Y, 2f));
 Totallength = Downlength + uplength;
  } @Override protected void OnDraw (Canvas Canvas) {Super.ondraw (Canvas);
  Canvas.save ();
  Drawborder (canvas);
  Drawtrim (canvas);
  if (ischecked) {Drawtick (canvas);
 } canvas.restore ();
  @Override protected parcelable onsaveinstancestate () {Bundle Bundle = new Bundle ();
  Bundle.putparcelable (Key_instance_state, Super.onsaveinstancestate ());
  Bundle.putboolean (Key_instance_state, ischecked);
 return bundle;  } @Override protected void Onrestoreinstancestate (parcelable state) {if (state instanceof Bundle) {Bundle Bundle
   = (Bundle) state;
   Boolean ischecked = Bundle.getboolean (key_instance_state);
   Setchecked (ischecked); Super.onrestoreinstancestate (Bundle.getparcelable (Key_instance_state));
  Return
 } super.onrestoreinstancestate (state);
  }//Toggle state private void Toggle () {ischecked =!ischecked;
  if (listener!= null) {listener.oncheckedchanged (this, ischecked);
  } if (ischecked) {checkedanimation ();
  else {uncheckedanimation ();
  }///is not selected to the selected animation private void Checkedanimation () {animatedvalue = 0f;
  Tickvalue = 0f;
  Mvalueanimator = Valueanimator.offloat (0f, 1.2f, 1f). Setduration (2 * DURATION/5);
  Mvalueanimator.setinterpolator (New Acceleratedecelerateinterpolator ());
  Mtickvalueanimator = Valueanimator.offloat (0f, 1f). Setduration (3 * DURATION/5);
  Mtickvalueanimator.setinterpolator (New Linearinterpolator ()); Mtickvalueanimator.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Override public void Onanimationu
    Pdate (Valueanimator valueanimator) {tickvalue = (float) valueanimator.getanimatedvalue ();
   Postinvalidate ();
  }
  }); Mvalueanimator.addupdatelistener (New ValueaniMator. Animatorupdatelistener () {@Override public void onanimationupdate (Valueanimator valueanimator) {Animatedvalue
    = (float) valueanimator.getanimatedvalue ();
   Postinvalidate ();
  }
  }); Mvalueanimator.addlistener (New Animatorlisteneradapter () {@Override public void Onanimationend (animator animation)
    {Mtickvalueanimator.start ();
  LOG.I (TAG, "Mtickvalueanimator.start ();");
 Mvalueanimator.start ();
  ///from selected to unchecked animation private void Uncheckedanimation () {animatedvalue = 0f;
  Mvalueanimator = Valueanimator.offloat (1f, 0f). Setduration (2 * DURATION/5);
  Mvalueanimator.setinterpolator (New Accelerateinterpolator ()); Mvalueanimator.addupdatelistener (New Valueanimator.animatorupdatelistener () {@Override public void Onanimationupdat
    E (Valueanimator valueanimator) {animatedvalue = (float) valueanimator.getanimatedvalue ();
   Postinvalidate ();
  }
  });
 Mvalueanimator.start ();
 ///Draw to hook private void Drawtick (Canvas Canvas) { float temp = Tickvalue * TOTALLENGTH;
  LOG.I (TAG, "temp:" + temp + "Downlength:" + downlength);
   if (Float.compare (Tickvalue, 0f) = = 0) {log.i (TAG, "startpoint:" + startpoint.x + "," + startpoint.y);
   Path.reset ();
  Path.moveto (Startpoint.x, STARTPOINT.Y);
   } if (Temp > Downlength) {path.moveto (startpoint.x, STARTPOINT.Y);
   Path.lineto (Breakpoint.x, BREAKPOINT.Y);
   LOG.I (TAG, "endPoint:" + endpoint.x + "," + endpoint.y); Path.lineto ((endpoint.x-breakpoint.x) * (temp-downlength)/Uplength + Breakpoint.x, (endpoint.y-breakpoint.y) * (Te
  Mp-downlength)/uplength + Breakpoint.y); else {log.i (TAG, "Down x:" + (breakpoint.x-startpoint.x) * temp/downlength + ", down Y:" + (Breakpoint.y-sta
   RTPOINT.Y) * temp/downlength); Path.lineto ((breakpoint.x-startpoint.x) * temp/downlength + startpoint.x, (breakpoint.y-startpoint.y) * TEMP/DOWNL
  Ength + startpoint.y);
 } canvas.drawpath (path, tickpaint); //Draw Border private void DrAwborder (Canvas Canvas) {float temp;
  if (Animatedvalue > 1f) {temp = Animatedvalue * Mradius;
  else {temp = Mradius;
 Canvas.drawcircle (center, center, temp, borderpaint); ///Draw checkbox internal private void Drawtrim (Canvas Canvas) {canvas.drawcircle (center, center, (mradius-mstrokewidth) *
 Animatedvalue, Trimpaint);
 @Override public void OnClick (view view) {toggle ();
 /** * To determine whether the checkbox is selected * * @return * * * public boolean ischecked () {return ischecked; /** * Set checkbox status * * @param ischecked Check/public void setchecked (Boolean ischecked) {This.setchecke
 D (ischecked, false); /** * Set checkbox status * * @param ischecked whether the * @param isanimation Toggle is animated/public void setchecked (Boole
  An ischecked, Boolean isanimation) {this.ischecked = ischecked;
   if (isanimation) {if (ischecked) {checkedanimation ();
   else {uncheckedanimation (); } else {animatedvalue = ischecked? 1f:0f;
   Tickvalue = 1f;
  Invalidate ();
  } if (listener!= null) {listener.oncheckedchanged (this, ischecked); } public interface Oncheckedchangelistener {void oncheckedchanged (Smoothcheckbox smoothcheckbox, Boolean ischecked
 ); }
}

Summarize

The above is the entire content of this article, I hope the content of this article for everyone's study or work can bring certain help, if you have questions you can message exchange.

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.