Android implements search buttons and clock complexity via path _android

Source: Internet
Author: User

The most complex graphics in Android are made by path, such as drawing a curve and then moving an object along with the curve, such as a search button, such as a simple clock implementation:

So what is path!

Definition: path is the way, which is the set of paths of the graph, which contains the coordinates of the path inside, and so on. We can get the coordinates of any point, the tangent value.

Then, to get a bit of the coordinates at the top of the path you need to use a class, pathmeasure;

Pathmesure:

Pathmeasure is a class used to measure path, mainly in the following ways:

Construction method

Public methods

As you can see, this is equivalent to a tool class for path, which is simple, so start the button and clock development we're going to do.

(1) Search button, first figure:


The first thing to do is to break it down and do it.
Create the path path to the Search button, and then create the path to rotate the outer ring,

 public void Initpath () {
    mpath_search = new Path ();
    Mpath_circle = new Path ();

    Mmeasure = new Pathmeasure ();

    Note that not to 360 degrees, otherwise the internal will automatically optimize, measurement can not be taken to the desired value
    RECTF oval1 = new RECTF ( -50, -50,,);     Magnifying glass ring
    Mpath_search.addarc (Oval1, 359.9f);

    RECTF oval2 = new RECTF ( -100, -100, MB);   Outer ring
    Mpath_circle.addarc (Oval2, -359.9f);

    Float[] pos = new float[2];

    Mmeasure.setpath (mpath_circle, false);        Magnifying glass handle position
    Mmeasure.getpostan (0, POS, null);

    Mpath_search.lineto (Pos[0], pos[1]);         Magnifying glass handle

    log.i ("TAG", "pos=" + pos[0] + ":" + pos[1]);

  

The effect we want is to start by clicking the Search button and turning it into a rotation, and then after the search is over, it becomes the search button.

So we can be certain of four states:

  Public  enum seach_state{
    start,end,none,searching
  }

The path is then dynamically drawn according to the state, and the dynamic drawing path uses the Pathmeasure to measure the current path's coordinates and then draw.

  private void DrawPath (Canvas c) {c.translate (MWIDTH/2, MHEIGHT/2);
        Switch (mstate) {case None:c.drawpath (mpath_search,mpaint);

      Break
        Case START:mMeasure.setPath (mpath_search,true);
        Path PATH = new Path ();
        Mmeasure.getsegment (Mmeasure.getlength () * curretnanimationvalue,mmeasure.getlength (), path, true);
        C.drawpath (Path,mpaint);

      Break
        Case SEARCHING:mMeasure.setPath (mpath_circle,true);
        Path Path_search = new Path (); Mmeasure.getsegment (Mmeasure.getlength () *curretnanimationvalue-30,mmeasure.getlength () *curretnAnimationValue,
        Path_search,true);
        C.drawpath (Path_search,mpaint);

      Break
        Case END:mMeasure.setPath (mpath_search,true);

        Path Path_view = new Path ();
        Mmeasure.getsegment (0,mmeasure.getlength () *curretnanimationvalue,path_view,true);
        C.drawpath (Path_view,mpaint);
    Break

 }

  }

The

is then calculated by using the property animation to return the currently drawn hundred percent, which computes the path to draw. The
below is the entire code:

Package Com.duoku.platform.demo.canvaslibrary.attract.view;
Import Android.animation.Animator;
Import Android.animation.ValueAnimator;
Import Android.content.Context;
Import Android.graphics.Canvas;
Import Android.graphics.Color;
Import Android.graphics.Paint;
Import Android.graphics.Path;
Import Android.graphics.PathMeasure;
Import Android.graphics.RectF;
Import Android.util.AttributeSet;
Import Android.util.Log;

Import Android.view.View;
 /** * Created by chenpengfei_d on 2016/9/7.
  * * public class Searchview extends View {private Paint mpaint;
  Private context Mcontext;
  Private Path mpath_circle;
  Private Path Mpath_search;
  Private Pathmeasure mmeasure;
  Private Valueanimator Mvalueanimator_search;
  Private long defaultduration=3000;
  private float Curretnanimationvalue;
  Private Seach_state mstate = seach_state.searching;
    Public Searchview {Super (context);
  Init (context);
    Public Searchview (context context, AttributeSet Attrs) {Super (context, attrs);
  Init (context);
    Public Searchview (context, AttributeSet attrs, int defstyleattr) {Super (context, attrs, defstyleattr);
  Init (context);
    "public void init" {this.mcontext = context;
    Initpaint ();
    Initpath ();

  Initanimation ();
    public void Initpaint () {mpaint = new Paint ();
    Mpaint.setdither (TRUE);
    Mpaint.setstrokecap (Paint.Cap.ROUND)//Set the pen effect Mpaint.setantialias (true);
    Mpaint.setcolor (color.red);
    Mpaint.setstrokewidth (3);
  Mpaint.setstyle (Paint.Style.STROKE);
    public void Initpath () {mpath_search = new Path ();

    Mpath_circle = new Path ();

    Mmeasure = new Pathmeasure ();     Note that not to 360 degrees, otherwise the internal will automatically optimize, measurement can not be taken to the desired value RECTF oval1 = new RECTF (-50,-50, 50, 50);

    Magnifying glass ring Mpath_search.addarc (Oval1, 359.9f);   RECTF oval2 = new RECTF (-100,-100, 100, 100);

    Outer ring Mpath_circle.addarc (Oval2, -359.9f);

    Float[] pos = new float[2]; MMeAsure.setpath (mpath_circle, false);

    Magnifying glass handle position Mmeasure.getpostan (0, POS, null);         Mpath_search.lineto (Pos[0], pos[1]);

  Magnifying glass hand log.i ("TAG", "pos=" + pos[0] + ":" + pos[1]); 

    public void Initanimation () {mvalueanimator_search = Valueanimator.offloat (0f,1.0f). Setduration (defaultduration);

    Mvalueanimator_search.addupdatelistener (Updatelistener);
  Mvalueanimator_search.addlistener (Animationlistener); Private Valueanimator.animatorupdatelistener Updatelistener = new Valueanimator.animatorupdatelistener () {@Overri De public void Onanimationupdate (Valueanimator animation) {Curretnanimationvalue = (float) animation.getanimate
      Dvalue ();
    Invalidate ();

  }
  }; Private Animator.animatorlistener Animationlistener = new Animator.animatorlistener () {@Override public void onAn Imationstart (animator animation) {} @Override public void Onanimationend (animator animation) {if (M State ==seach_stAte.
        START) {setstate (seach_state.searching); @Override public void Onanimationcancel (animator animation) {} @Override public void Onani
  Mationrepeat (animator animation) {}};

    @Override protected void OnDraw (Canvas Canvas) {Super.ondraw (Canvas);
  DrawPath (canvas);
  } private int mwidth,mheight;
    @Override protected void onsizechanged (int w, int h, int oldw, int oldh) {super.onsizechanged (W, H, OLDW, OLDH);
    Mwidth = W;

  Mheight = h;
    } private void DrawPath (Canvas c) {c.translate (MWIDTH/2, MHEIGHT/2);
        Switch (mstate) {case None:c.drawpath (mpath_search,mpaint);

      Break
        Case START:mMeasure.setPath (mpath_search,true);
        Path PATH = new Path ();
        Mmeasure.getsegment (Mmeasure.getlength () * curretnanimationvalue,mmeasure.getlength (), path, true);
        C.drawpath (Path,mpaint);

      Break Case SEARCHING:mMeasure.setPath(mpath_circle,true);
        Path Path_search = new Path (); Mmeasure.getsegment (Mmeasure.getlength () *curretnanimationvalue-30,mmeasure.getlength () *curretnAnimationValue,
        Path_search,true);
        C.drawpath (Path_search,mpaint);

      Break
        Case END:mMeasure.setPath (mpath_search,true);

        Path Path_view = new Path ();
        Mmeasure.getsegment (0,mmeasure.getlength () *curretnanimationvalue,path_view,true);
        C.drawpath (Path_view,mpaint);
    Break
    } public void SetState (Seach_state state) {this.mstate = state;
  Startsearch ();
        public void Startsearch () {switch (mstate) {case START:mValueAnimator_search.setRepeatCount (0);

      Break
        Case SEARCHING:mValueAnimator_search.setRepeatCount (Valueanimator.infinite);
        Mvalueanimator_search.setrepeatmode (Valueanimator.reverse);

      Break
        Case END:mValueAnimator_search.setRepeatCount (0);
    Break } mValueanimator_search.start ();

 public enum seach_state{Start,end,none,searching}}

(Learning point: path can be combined, you can put different path into a path inside, and then the unified drawing)

(2) Clock effect:

Tell me about the clock, a lot of clocks on the internet are achieved by canvas drawing basic graphics, not through path to achieve, using the path is to achieve more flexible control of the clock's rendering effect, such as we want to let the outermost circle counterclockwise rotation, as well as the top add small stars what, Using path will be more flexible.

The implementation of the clock is divided into parts:

1, create the outer circle path Path

2, create the Tick path path, to distinguish the whole point, draw points in time

3, draw the pointer, (this is the use of canvas drawn line segments, you can use path, you can test yourself)

You need to calculate the angle of the current hour hand, minute hand, second hand, and then draw

Overall code:

Package Com.duoku.platform.demo.canvaslibrary.attract.view;
Import Android.content.Context;
Import Android.graphics.Canvas;
Import Android.graphics.Color;
Import Android.graphics.Paint;
Import Android.graphics.Path;
Import Android.graphics.PathMeasure;
Import Android.os.Handler;
Import Android.util.AttributeSet;

Import Android.view.View;

Import Java.util.Calendar;
 /** * Created by chenpengfei_d on 2016/9/8.
  * * public class Timeview extends View {private Paint mpaint,mpaint_time;
  Private Paint mpaint_h,mpaint_m,mpaint_s;
  Private Path mpath_circle;
  Private Path Mpath_circle_h;
  Private Path mpath_circle_m;
  Private Path mpath_h,mpath_m,mpath_s;

  Private Path mpath_duration;
  Private Pathmeasure mmeasure;
  Private Pathmeasure Mmeasure_h;
  Private Pathmeasure mmeasure_m;
  Private Handler Mhandler = new Handler ();
  Private Runnable clockrunnable;
  Private Boolean isrunning;
    Public Timeview {Super (context);
  Init (); Public Timeview (COntext context, AttributeSet attrs) {Super (context, attrs);
  Init ();
    Public Timeview (context, AttributeSet attrs, int defstyleattr) {Super (context, attrs, defstyleattr);
  Init ();
  int t = 3;
    public void init () {//init brush mpaint = new Paint ();
    Mpaint.setdither (TRUE);
    Mpaint.setantialias (TRUE);
    Mpaint.setstyle (Paint.Style.STROKE);
    Mpaint.setstrokewidth (2);
    Mpaint.setstrokecap (Paint.Cap.ROUND);
    Mpaint.setstrokejoin (Paint.Join.ROUND);
    Mpaint.setcolor (color.red);
    Mpaint_time = new Paint ();
    Mpaint_time.setdither (TRUE);
    Mpaint_time.setantialias (TRUE);
    Mpaint_time.setstyle (Paint.Style.STROKE);
    Mpaint_time.setstrokewidth (2);
    Mpaint_time.settextsize (15);
    Mpaint_time.setstrokecap (Paint.Cap.ROUND);
    Mpaint_time.setstrokejoin (Paint.Join.ROUND);

    Mpaint_time.setcolor (color.red);
    Mpaint_h = new Paint ();
    Mpaint_h.setdither (TRUE);
    Mpaint_h.setantialias (TRUE); Mpaint_h.setstyle (PainT.style.stroke);
    Mpaint_h.setstrokewidth (6);
    Mpaint_h.settextsize (15);
    Mpaint_h.setstrokecap (Paint.Cap.ROUND);
    Mpaint_h.setstrokejoin (Paint.Join.ROUND);

    Mpaint_h.setcolor (color.red);
    Mpaint_m = new Paint ();
    Mpaint_m.setdither (TRUE);
    Mpaint_m.setantialias (TRUE);
    Mpaint_m.setstyle (Paint.Style.STROKE);
    Mpaint_m.setstrokewidth (4);
    Mpaint_m.settextsize (15);
    Mpaint_m.setstrokecap (Paint.Cap.ROUND);
    Mpaint_m.setstrokejoin (Paint.Join.ROUND);

    Mpaint_m.setcolor (color.red);
    mpaint_s = new Paint ();
    Mpaint_s.setdither (TRUE);
    Mpaint_s.setantialias (TRUE);
    Mpaint_s.setstyle (Paint.Style.STROKE);
    Mpaint_s.setstrokewidth (2);
    Mpaint_s.settextsize (15);
    Mpaint_s.setstrokecap (Paint.Cap.ROUND);
    Mpaint_s.setstrokejoin (Paint.Join.ROUND);
    Mpaint_s.setcolor (color.red);
    Initialize scale mpath_circle = new Path ();
    Mpath_circle.addcircle (0,0,250, Path.Direction.CCW);
    Mpath_circle_h = new Path (); Mpath_circle_h.addCircle (0,0,220, Path.Direction.CCW);
    Mpath_circle_m = new Path ();
    Mpath_circle_m.addcircle (0,0,235, Path.Direction.CCW);
    Initialize pathmeasure to measure path coordinates, mmeasure = new Pathmeasure ();
    Mmeasure.setpath (mpath_circle,true);
    Mmeasure_h = new Pathmeasure ();
    Mmeasure_h.setpath (mpath_circle_h,true);
    Mmeasure_m = new Pathmeasure ();
    Mmeasure_m.setpath (mpath_circle_m,true);
    Get tick path mpath_duration = new Path ();
      for (int i = i>0; I-) {path PATH = new Path ();
      float pos [] = new float[2];
      float tan [] = new float[2];
      float Pos2 [] = new float[2];
      float tan2 [] = new float[2];
      float POS3 [] = new float[2];
      float TAN3 [] = new float[2];
      Mmeasure.getpostan (Mmeasure.getlength () *i/60,pos,tan);
      Mmeasure_h.getpostan (Mmeasure_h.getlength () *i/60,pos2,tan2);

      Mmeasure_m.getpostan (Mmeasure_m.getlength () *i/60,pos3,tan3);
      float x = pos[0];
      Float y = pos[1];
      float x2 = pos2[0];float y2 = pos2[1];
      Float x3 = pos3[0];
      float y3 = pos3[1];

      Path.moveto (x, y);
        if (i% 5 ==0) {Path.lineto (x2,y2);
        if (t>12) {t = t-12;
        String time = t++ + "";
        Path path_time = new Path ();
        Mmeasure_h.getpostan (Mmeasure_h.getlength () * (i-1)/60,pos2,tan2);
        Mpaint.gettextpath (Time,0,time.length (), (x2-(X2/15)), y2-(Y2/15), path_time);
        Path.close ();
      Path.addpath (Path_time);
      }else{Path.lineto (X3,Y3);
      } mpath_duration.addpath (path);
          clockrunnable = new Runnable () {//The thing that you do is refresh the interface @Override public void Run () {//) every second.
          Postinvalidate ();
        Mhandler.postdelayed (this, 1000);
    }
      };
    } mpath_h = new Path ();

    Mpath_h.rlineto (50,30);
    Mpath_m = new Path ();

    Mpath_m.rlineto (80,80);
    mpath_s = new Path ();
  Mpath_s.rlineto (130,50);
  } private int mwidth,mheight; @Override
  protected void onsizechanged (int w, int h, int oldw, int oldh) {super.onsizechanged (W, H, OLDW, OLDH);
    Mwidth = W;
  Mheight = h;
    } @Override protected void OnDraw (Canvas Canvas) {Super.ondraw (Canvas);
      if (!isrunning) {isrunning = true;
    Mhandler.postdelayed (clockrunnable,1000);

      }else{canvas.translate (MWIDTH/2,MHEIGHT/2);
      Canvas.drawpath (Mpath_circle,mpaint);
      Canvas.save ();

      Canvas.drawpath (Mpath_duration,mpaint_time);

      Canvas.drawpoint (0,0,mpaint_time);
    Drawclockpoint (canvas);
  }} private Calendar cal;
  private int hour;
  private int min;
  private int second;
  private float Hourangle,minangle,secangle;
    /** * Draw three pointers * @param canvas/private void drawclockpoint (canvas canvas) {cal = Calendar.getinstance (); hour = Cal.get (calendar.hour);//calendar.hour gets 12-hour system, Calendar.hour_of_day gets 24-hour min = Cal.get (calendar.minute
    );
    Second = Cal.get (Calendar.second);Hourangle = (float) HOUR/12 * 360 + (float) min/60 * (360/12);//360/12 refers to the angle between each number in the calculation
    = (float) min/60 * 360;
    Secangle = (float) second/60 * 360;
    The following will rotate the time, minute, and second pointers according to their respective offset angles, and save the original state of the canvas Canvas.save () before each rotation;
    Canvas.rotate (hourangle,0, 0);
    Canvas.drawline (0, 0, MWIDTH/6, getheight ()/6-65, mpaint_h);/clockwise length set to Canvas.restore ();
    Canvas.save ();
    Canvas.rotate (minangle,0, 0);
    Canvas.drawline (0, 0, MWIDTH/6, getheight ()/6-90, mpaint_m);/the minute hand length is set to Canvas.restore ();
    Canvas.save ();
    Canvas.rotate (secangle,0, 0);
  Canvas.drawline (0, 0, MWIDTH/6, getheight ()/6-110, mpaint_s);//The second hand length is set to Canvas.restore ();

 }
}

This is actually not a particularly complex animation, perhaps you have any good ideas, you can use the path + attribute animation to achieve a more good-looking effect;

For example, the effect of the sky, such as the dynamic drawing text + path to achieve similar PPT in the play of some special effects, such as electronic books automatically page.

(3) next to introduce a knowledge, is SVG:

What is SVG?

His scientific name is called Scalable Vector graphics, is based on Extensible Markup Language (a subset of standard universal Markup Language), used to describe a two-dimensional vector graphics graphics format.

The graphical form of this format can be loaded into the Android path.

Since it can be loaded into the path, is it possible to achieve more complex effects, look at the bottom of the picture: (Write Tomorrow)

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

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.