前几天在“Android绘图之渐隐动画”一文中通过画线实现了渐隐动画,但里面有个问题,画笔较粗(大于1)时线段之间会有裂隙,我又改进了一下。这次效果好多了。
先看效果吧:
然后我们来说说基本的做法:
- 根据画笔宽度,计算每一条线段两个顶点对应的四个点,四点连线,包围线段,形成一个路径。
- 后一条线段的路径的前两个点,取(等于)前一条线段的后两点,这样就衔接起来了。
把Path的Style修改为FILL,效果是这样的:
可以看到一个个四边形,连成了路径。
好啦,现在说说怎样根据两点计算出包围它们连线的路径所需的四个点。
先看一张图:
在这张图里,黑色细线是我们拿到的两个触摸点相连得到的。当画笔宽度大于1(比如为10)时,其实经过这条黑线的两个端点并且与这条黑线垂直相交的两条线(蓝线),就可以计算出来,蓝线的长度就是画笔的宽度,结合这些就可以计算出红色的四个点。而红色的四个点就围住了线段,形成路径。
这里面用到两点连线的公式,采用点斜式:
y = k*x + b
黑线的斜率是:
k = (y2 - y1) / (x2 - x1)
垂直相交的两条线的斜率的关系是:
k1 * k2 = -1
所以,蓝线的斜率就可以计算出来了。有了斜率和线上的一个点,就可以求出这条线的点斜式中的b,点斜式就出来了。
然后,利用两点间距离公式:
已知一个点,这个点与另一个点的距离(画笔宽度除以2),斜率,代入两点间距离公式和蓝线的点斜式,就可以计算出两个红色的点了。
计算时用到的是一元二次方程a*x*x + bx + c = 0
,求 x 时用的公式是:
好啦,最后,上代码:
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,欢迎关注我的订阅号“程序视界”.
*/
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){
//point-k formula
// y= kx + b
//distance formula of two points
// d