Android Custom View drawing implements drag-and-shadow animation _android

Source: Internet
Author: User
Tags abs int size pow

A few days ago in the "fade animation of the Android Graphics" in the text to achieve the fade animation, but there is a problem, the brush is thicker (greater than 1) when there will be cracks between the line, I have improved a bit. The effect is much better this time.

First look at the effect bar:

And then we'll talk about the basic approach:
• Calculate the four points corresponding to the two vertices of each line, four-point lines, and enclose the segments to form a path according to the brush width.
• The first two points of the path of the last line segment, followed by (equal to) the last two o'clock of the preceding line, so that they are connected.

Modify the path's style to fill, and the effect is this:

Can see a four-way, connected to the path.

OK, now tell me how to calculate the four points that are required to enclose the path of their connection based on two points.

First look at a picture:

In this picture, the black thread is connected to the two touch points we get. When the brush width is greater than 1 (for example, 10), in fact, through the two endpoints of the black line and two lines (blue lines) perpendicular to the black line, it is possible to calculate that the length of the blue lines is the width of the brush, combining which you can calculate the red four dots. The red four points surround the line segment and form a path.

Here we use the two-point line formula, using the dot-italic:

y = k*x + b

The slope of the black line is:

K = (y2-y1)/(X2-X1)

The slope relationship between the two lines that are vertically intersecting is:

K1 * K2 =-1

So the slope of the Blue Line can be calculated. With a slope and a point on the line, you can find the point of this line in the diagonal of B, point oblique type came out.

Then, use the distance formula between two points:

A point is known, the distance between the point and the other point (the brush width divided by 2), the slope, the distance formula between two points, and the point skew of the Blue line, you can calculate the two red dots.

The calculation uses a two-time equation a*x*x + bx + c = 0, the formula for X is:

Okay, finally, on the code:

Package com.example.disappearinglines;
Import Android.content.Context;
Import Android.graphics.Canvas;
Import Android.graphics.Paint;
Import Android.graphics.Path;
Import Android.graphics.PointF;
Import Android.graphics.RectF;
Import Android.os.Handler;
Import Android.os.Message;
Import Android.os.SystemClock;
Import Android.support.annotation.NonNull;
Import Android.util.AttributeSet;
Import Android.util.Log;
Import Android.util.TypedValue;
Import android.view.MotionEvent;

Import Android.view.View;
Import java.util.ArrayList;
Import java.util.Collection;
Import Java.util.Iterator;
Import java.util.List;

Import Java.util.ListIterator;
 /** * Created by Foruok, please pay attention to my subscription number "program Horizon".
  */public class Disappearingdoodleview extends View {public static float CONVERTDIPTOPX (context context, float Fdip) { float fPx = typedvalue.applydimension (Typedvalue.complex_unit_dip, Fdip, Context.getresources (). GetDisplayMetrics ()
  );
 return fPx;
 Final static String TAG = "Doodleview"; Class lineelement {static final public int alpha_step = 8;
   Public lineelement (float pathwidth) {mpaint = new Paint ();
   Mpaint.setargb (255, 255, 0, 0);
   Mpaint.setantialias (TRUE);
   Mpaint.setstrokewidth (0);
   Mpaint.setstrokecap (Paint.Cap.BUTT);
   Mpaint.setstyle (Paint.Style.FILL);
   MPath = new Path ();
   Mpathwidth = Pathwidth;
   for (int i= 0; i < mpoints.length; i++) {mpoints[i] = new PointF ();
  } public void Setpaint (Paint Paint) {mpaint = Paint;
   public void Setalpha (int alpha) {Mpaint.setalpha (alpha);
  Mpathwidth = (Alpha * mpathwidth)/255; Private Boolean caculatepoints (float k, float B, float x1, float y1, float distance, PointF pt1, PointF pt2) {//po Int-k Formula//y= KX + B//distance formula of two points//distance*distance = Math.pow ((x-x1), 2) + MATH.P
   ow ((y-y1), 2)//|
   V//ax*x + bx + c = 0;
   // | V//x = (-B-+ math.sqrt (b*b-4*a*c))/(2*a) Double A1 = Math.pow (K, 2)+ 1;
   Double B1 = 2* K * (B-Y1)-2 * x1;
   Double C1 = Math.pow (x1, 2) + Math.pow (b-y1, 2)-Math.pow (distance, 2);
   Double criterion = Math.pow (B1, 2)-4*a1*c1;
    if (Criterion > 0) {criterion = math.sqrt (criterion);
    pt1.x = (float) ((-b1 + criterion)/(2 * A1));
    PT1.Y = k * pt1.x + B;
    pt2.x = (float) ((-b1-criterion)/(2 * A1));
    Pt2.y = k * pt2.x + B;
   return true;
  return false;
   } private void Swappoint (PointF pt1, PointF pt2) {float t = pt1.x;
   pt1.x = pt2.x;
   pt2.x = t;
   t = pt1.y;
   Pt1.y = pt2.y;
  Pt2.y = t;
   public Boolean updatepathpoints () {Float distance = MPATHWIDTH/2;
    if (Math.Abs (MENDX-MSTARTX) < 1) {mpoints[0].x = mstartx + distance;
    Mpoints[0].y = mstarty-distance;
    mpoints[1].x = mstartx-distance;
    Mpoints[1].y = MPOINTS[0].Y;
    mpoints[2].x = mpoints[1].x;
    MPOINTS[2].Y = Mendy + distance;
    mpoints[3].x = mpoints[0].x;
   Mpoints[3].y = MPOINTS[2].Y; }else if (Math.Abs (Mendy-mstarty) < 1) {mpoints[0].x = mstartx-distance;
    Mpoints[0].y = mstarty-distance;
    mpoints[1].x = mpoints[0].x;
    MPOINTS[1].Y = Mstarty + distance;
    mpoints[2].x = mendx + distance;
    Mpoints[2].y = MPOINTS[1].Y;
    mpoints[3].x = mpoints[2].x;
   Mpoints[3].y = MPOINTS[0].Y;
    }else{//point-k Formula//y= kx + B Float kLine = (mendy-mstarty)/(MENDX-MSTARTX);
    float kvertline = -1/kline;
    Float B = mstarty-(kvertline * mstartx); if (!caculatepoints (Kvertline, B, Mstartx, mstarty, distance, mpoints[0), mpoints[1]) {String info = String.Format (TA G, "startpt, criterion < 0, (%.2f,%.2f)--> (%.2f,%.2f), KLine-%.2f, Kvertline-%.2f, B-%.2f", Mstartx,
     Mstarty, Mendx, Mendy, KLine, kvertline, b);
     LOG.I (TAG, info);
    return false;
    } B = Mendy-(kvertline * mendx); if (!caculatepoints (Kvertline, B, Mendx, Mendy, distance, mpoints[2), mpoints[3]) {String info = StrinG.format (TAG, "endpt, criterion < 0, (%.2f,%.2f)--> (%.2f,%.2f), KLine-%.2f, Kvertline-%.2f, B-%.2f",
     Mstartx, Mstarty, Mendx, Mendy, KLine, kvertline, b);
     LOG.I (TAG, info);
    return false; }//reorder points to unti-clockwise if (Mstartx < mendx) {if (Mstarty < Mendy) {if (mpoints[0].x &L T
      mpoints[1].x) {swappoint (mpoints[0], mpoints[1]);
      } if (Mpoints[2].x > mpoints[3].x) {swappoint (mpoints[2), mpoints[3]);
      }}else{if (mpoints[0].x > mpoints[1].x) {swappoint (mpoints[0], mpoints[1]);
      } if (Mpoints[2].x < mpoints[3].x) {Swappoint (mpoints[2), mpoints[3]); }}else{if (Mstarty < Mendy) {if (mpoints[0].x < mpoints[1].x) {Swappoint (mpoints[0], MP
      OINTS[1]);
      } if (Mpoints[2].x > mpoints[3].x) {swappoint (mpoints[2), mpoints[3]); }}else{if (mpoints[0].x > mpoints[1].x) {swappoinT (Mpoints[0], mpoints[1]);
      } if (Mpoints[2].x < mpoints[3].x) {Swappoint (mpoints[2), mpoints[3]);
  }}} return true;
   Mpath.moveto (mpoints[0].x, MPOINTS[0].Y);
   Mpath.lineto (mpoints[1].x, MPOINTS[1].Y);
   Mpath.lineto (mpoints[2].x, MPOINTS[2].Y);
   Mpath.lineto (mpoints[3].x, MPOINTS[3].Y);
  Mpath.close ();
   }//For middle line public void updatepathwithstartpoints (PointF pt1, PointF pt2) {mpath.reset ();
   Mpath.moveto (pt1.x, PT1.Y);
   Mpath.lineto (pt2.x, PT2.Y);
   Mpath.lineto (mpoints[2].x, MPOINTS[2].Y);
   Mpath.lineto (mpoints[3].x, MPOINTS[3].Y);
  Mpath.close ();
  public float mstartx =-1;
  public float Mstarty =-1;
  public float mendx =-1;
  public float Mendy =-1;
  Public Paint Mpaint;
  Public Path MPath; Public pointf[] mpoints = new Pointf[4];
 Path ' s vertex float mpathwidth; Private Lineelement McurRentline = null;
 Private list<lineelement> mlines = null;
 private float Mlaserx = 0;
 private float mlasery = 0;
 Final Paint mpaint = new Paint ();
 private int mwidth = 0;
 private int mheight = 0;
 Private long melapsed = 0;
 Private float mstrokewidth = 20;
 Private float Mcircleradius = 10; Private Handler Mhandler = new Handler () {@Override public void Handlemessage (msg) {Disappearingdoodleview.
  This.invalidate ();

 }
 };
  Public Disappearingdoodleview {Super (context);
 Initialize (context);
  Public Disappearingdoodleview (context, AttributeSet attrs) {Super (context, attrs);
 Initialize (context);
  } private void Initialize {Mstrokewidth = convertdiptopx (context, 22);
  Mcircleradius = convertdiptopx (context, 10);
  Mpaint.setargb (255, 255, 0, 0);
  Mpaint.setantialias (TRUE);
  Mpaint.setstrokewidth (0);
 Mpaint.setstyle (Paint.Style.FILL); @Override protected void onsizechanged (int w, int h, int olDW, int oldh) {mwidth = W;
  Mheight = h;
 Adjustlasterposition ();
  private void Adjustlasterposition () {if (Mlaserx-mcircleradius < 0) Mlaserx = Mcircleradius;
  else if (Mlaserx + Mcircleradius > Mwidth) Mlaserx = Mwidth-mcircleradius;
  if (Mlasery-mcircleradius < 0) mlasery = Mcircleradius;
 else if (mlasery + Mcircleradius > Mheight) mlasery = Mheight-mcircleradius;
  } private void Updatelaserposition (float x, float y) {Mlaserx = x;
  Mlasery = y;
 Adjustlasterposition ();
  @Override protected void OnDraw (Canvas Canvas) {//canvas.drawtext ("ABCDE", mpaint);

  melapsed = Systemclock.elapsedrealtime ();
   if (mlines!= null) {updatepaths ();
    for (Lineelement e:mlines) {if (E.mstartx < 0 | | E.mendy < 0 | | e.mpath.isempty ()) continue;
    Canvas.drawline (E.mstartx, E.mstarty, E.mendx, E.mendy, E.mpaint);
   Canvas.drawpath (E.mpath, e.mpaint);
  } compactpaths (); } canvas.drawcircle (Mlaserx, Mlasery, Mcircleradius,Mpaint); Private Boolean isvalidline (float x1, float y1, float x2, float y2) {return math.abs (x1-x2) > 1 | |
 Math.Abs (Y1-y2) > 1;
  @Override public boolean ontouchevent (Motionevent event) {float x = Event.getx ();

  Float y = event.gety ();
  int action = Event.getaction (); if (action = = motionevent.action_up) {//end one line after the finger release if (Isvalidline Mcurrentline.mstartx, Mcurrentl
    Ine.mstarty, x, y)) {mcurrentline.mendx = x;
    Mcurrentline.mendy = y;
   Addtopaths (Mcurrentline);
   }//mcurrentline.updatepathpoints ();
   Mcurrentline = null;
   Updatelaserposition (x, y);
   Invalidate ();
  return true;
   } if (action = = motionevent.action_down) {mlines = null;

   Mcurrentline = new Lineelement (mstrokewidth);
   Mcurrentline.mstartx = x;
   Mcurrentline.mstarty = y;
   Updatelaserposition (x, y);
  return true; } if (action = = motionevent.action_move) {if (Isvalidline (Mcurrentline.mstartx, Mcurrentline.mstarty, X, y)) {MCuRrentline.mendx = x;
    Mcurrentline.mendy = y;

    Addtopaths (Mcurrentline);
    Mcurrentline = new Lineelement (mstrokewidth);
    Mcurrentline.mstartx = x;

    Mcurrentline.mstarty = y;
   Updatelaserposition (x, y);
  }else{//do Nothing and wait for next point}} if (Mhandler.hasmessages (1)) {mhandler.removemessages (1);
  msg = new Message ();
  Msg.what = 1;

  mhandler.sendmessagedelayed (msg, 0);
 return true;
  private void Addtopaths (lineelement element) {if (Mlines = null) {Mlines = new arraylist<lineelement> ();
 } mlines.add (Element);
  private void Updatepaths () {int size = Mlines.size ();


  if (size = = 0) return;
  Lineelement line = null;
  int j = 0;
   for (; J < size; J + +) {line = Mlines.get (j);
  if (line.updatepathpoints ()) break;
   } if (j = = size) {mlines.clear ();
  Return
   else {for (j--J >= 0; j--) {mlines.remove (0);
  } line.updatepath ();

  Size = Mlines.size (); LineelemENT lastline = null;
   for (int i = 1; i < size; i++) {line = Mlines.get (i);
    if (line.updatepathpoints ()) {if (lastline = = null) {lastline = Mlines.get (i-1);
    } line.updatepathwithstartpoints (Lastline.mpoints[3], lastline.mpoints[2]);
   LastLine = null;
    }else{Mlines.remove (i);
   Size = Mlines.size ();
  }} public void Compactpaths () {int size = Mlines.size ();
  int index = size-1;
  if (size = = 0) return;
  int basealpha = 255-lineelement.alpha_step;
  int Itselfalpha;
  Lineelement Line;
   for (; index >=0; index--, Basealpha-= lineelement.alpha_step) {line = Mlines.get (index);
   Itselfalpha = Line.mPaint.getAlpha ();
     if (Itselfalpha = = 255) {if (basealpha <= 0 | | Line.mpathwidth < 1) {++index;
    Break
   } line.setalpha (Basealpha);
    }else{Itselfalpha-= Lineelement.alpha_step;
     if (itselfalpha <= 0 | | | Line.mpathwidth < 1) {++index;
    Break } line.setalpha (Itselfalpha);
  } if (index >= size) {//All sub-path should disappear mlines = null;
   else if (index >= 0) {//log.i (TAG, "compactpaths from" + Index + "to" + (size-1));
  Mlines = mlines.sublist (index, size);
  }else{//No sub-path should disappear} long interval = 40-systemclock.elapsedrealtime () + melapsed;
  if (interval < 0) interval = 0;
  msg = new Message ();
  Msg.what = 1;
 Mhandler.sendmessagedelayed (msg, interval);

 }
}

This painting, the efficiency is not very good, have not thought how to improve, we can discuss the discussion.

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.