《Android自定义控件入门到精通》文章索引 ☞ https://blog.csdn.net/Jhone_csdn/article/details/118146683
《Android自定义控件入门到精通》所有源码 ☞ https://gitee.com/zengjiangwen/Code
文章目录
PathEffect
路径效果,有六个实现类。
DashPathEffect
DashPathEffect(float intervals[], float phase) 虚线路径效果
- intervals:描述虚线效果的数组,按这个数组描述循环绘制效果
- phase:开始绘制的偏移量
示例:
@Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(4);
Path path = new Path();
path.moveTo(50, 50);
path.lineTo(500, 50);
paint.setColor(Color.WHITE);
canvas.drawPath(path, paint);
canvas.translate(0, 50);
float[] intervals = new float[]{10, 10};//画10、空10
paint.setPathEffect(new DashPathEffect(intervals, 0));
canvas.drawPath(path, paint);
canvas.translate(0, 50);
float[] intervals1 = new float[]{10, 30};//画10、空30
paint.setPathEffect(new DashPathEffect(intervals1, 0));
paint.setColor(Color.YELLOW);
canvas.drawPath(path, paint);
canvas.translate(0, 50);
float[] intervals2 = new float[]{10, 20, 30, 20};//画10、空20、画30、空20
paint.setPathEffect(new DashPathEffect(intervals2, 0));
paint.setColor(Color.RED);
canvas.drawPath(path, paint);
canvas.translate(0, 50);
float[] intervals3 = new float[]{10, 20, 30, 20};//画10、空20、画30、空20
paint.setPathEffect(new DashPathEffect(intervals3, 30));//起点偏移30
paint.setColor(Color.RED);
canvas.drawPath(path, paint);
}
用这个phase偏移量还能实现虚线运动的效果
private Paint mPaint;
private Path mPath;
private void init() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(4);
mPath = new Path();
mPath.moveTo(20,120);
mPath.cubicTo(60,20,180,220,240,120);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(mPath, mPaint);
}
//点击事件触发这个方法
public void showAnimator() {
ValueAnimator animator = ValueAnimator.ofFloat(0, 45);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setDuration(2000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
mPaint.setPathEffect(new DashPathEffect(new float[]{5, 10, 20, 10}, value));
invalidate();
}
});
animator.start();
}
PathDashPathEffect
PathDashPathEffect(Path shape, float advance, float phase,Style style),图章路径效果
- shape:图章形状
- advance:两个图案之间的距离
- phase:起始偏移量,跟DashPathEffect中的phase一个意思
- style:设置路径转角图案的处理方式
Style:
- PathDashPathEffect.Style.TRANSLATE 平移改变位置处理转角
- PathDashPathEffect.Style.ROTATE 旋转改变角度处理转角
- PathDashPathEffect.Style.MORPH 变形改变形状处理转角
不知道大家对PS的图案图章工具有没有了解,给大家演示一下:
PathDashPathEffect路径效果也是差不多是这个样子的
@Override
protected void onDraw(Canvas canvas) {
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.FILL);
//创建图章形状
Path shape = new Path();
shape.moveTo(0, 15);
shape.quadTo(0, 36, 25, 50);
shape.quadTo(46, 36, 46, 15);
shape.cubicTo(46, -2, 25, -2, 23, 12);
shape.cubicTo(21, -2, 0, -2, 0, 15);
//创建路径
Path path = new Path();
path.moveTo(20, 50);
path.lineTo(400, 50);
path.quadTo(300, 300, 200, 200);
//设置图章效果样式为 Style.TRANSLATE
mPaint.setPathEffect(new PathDashPathEffect(shape, 80, 0, PathDashPathEffect.Style.TRANSLATE));
canvas.drawPath(path, mPaint);
//设置图章效果样式为 Style.ROTATE
mPaint.setPathEffect(new PathDashPathEffect(shape, 80, 0, PathDashPathEffect.Style.ROTATE));
canvas.translate(0, 250);
canvas.drawPath(path, mPaint);
//设置图章效果样式为 Style.MORPH
mPaint.setPathEffect(new PathDashPathEffect(shape, 80, 0, PathDashPathEffect.Style.MORPH));
canvas.translate(0, 250);
canvas.drawPath(path, mPaint);
}
CornerPathEffect
CornerPathEffect(float radius),圆角路径效果
- radius:圆角的半径
@Override
protected void onDraw(Canvas canvas) {
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(2);
Path path=new Path();
path.lineTo(100,260);
path.lineTo(125,60);
path.lineTo(200,180);
path.lineTo(250,90);
path.lineTo(320,200);
path.lineTo(400,20);
path.lineTo(499,160);
//设置圆角路径效果,圆角半径为10
mPaint.setPathEffect(new CornerPathEffect(10));
canvas.drawPath(path,mPaint);
//设置圆角路径效果,圆角半径为50
mPaint.setPathEffect(new CornerPathEffect(50));
canvas.translate(0,300);
canvas.drawPath(path,mPaint);
}
可以看出,半径越大,圆角越圆润
SumPathEffect
SumPathEffect(PathEffect first, PathEffect second),几个效果叠加
@Override
protected void onDraw(Canvas canvas) {
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(2);
//创建一条路径
Path path = new Path();
path.lineTo(100, 260);
path.lineTo(125, 60);
path.lineTo(200, 180);
path.lineTo(250, 90);
path.lineTo(320, 200);
path.lineTo(400, 20);
path.lineTo(499, 160);
//圆角路径效果
CornerPathEffect cornerPathEffect = new CornerPathEffect(50);
//虚线路径效果
DashPathEffect dashPathEffect = new DashPathEffect(new float[]{10, 10}, 0);
//堆叠效果,圆角效果在下,虚线效果在上
mPaint.setPathEffect(new SumPathEffect(cornerPathEffect, dashPathEffect));
canvas.drawPath(path, mPaint);
//堆叠效果,虚线效果在下,圆角效果在上
canvas.translate(0, 200);
mPaint.setPathEffect(new SumPathEffect(dashPathEffect, cornerPathEffect));
mPaint.setColor(Color.WHITE);
canvas.drawPath(path, mPaint);
}
拿上面那条路径来说,也就是先画一条圆角路径效果,再画一条虚线路径效果,然后把两个效果堆叠在一起形成新的一种效果.。
ComposePathEffect
ComposePathEffect(PathEffect outerpe, PathEffect innerpe),复合效果路径
@Override
protected void onDraw(Canvas canvas) {
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(2);
//创建一条路径
Path path = new Path();
path.lineTo(100, 260);
path.lineTo(125, 60);
path.lineTo(200, 180);
path.lineTo(250, 90);
path.lineTo(320, 200);
path.lineTo(400, 20);
path.lineTo(499, 160);
//圆角路径效果
CornerPathEffect cornerPathEffect = new CornerPathEffect(50);
//虚线路径效果
DashPathEffect dashPathEffect = new DashPathEffect(new float[]{10, 10}, 0);
//复合效果,先应用虚线路径效果,再在虚线路径效果上应用圆角路径效果
mPaint.setPathEffect(new ComposePathEffect(cornerPathEffect, dashPathEffect));
canvas.drawPath(path, mPaint);
//复合效果,先应用圆角路径效果,再在圆角路径效果上应用虚线路径效果
canvas.translate(0, 200);
mPaint.setPathEffect(new ComposePathEffect(dashPathEffect, cornerPathEffect));
mPaint.setColor(Color.WHITE);
canvas.drawPath(path, mPaint);
}
可以看到,跟堆叠效果不一样的是,应用Effect的顺序不一样,最终效果就不一样,这里一定要注意这个顺序了:outer(inner(path)),inner是优先执行的。大家可能会觉得疑问,为什么上面红色路径只有虚线效果,没有圆角效果,这个没有为什么哈,虚线变不圆而已(强行解释)
DiscretePathEffect
DiscretePathEffect(float segmentLength, float deviation),离散路径效果
- segmentLength :可以理解为离散频率
- deviation:可以理解为做离散运动的距离,偏移量
例如DiscretePathEffect(2,10),可以理解为:每2个像素长度为单位做离散运动,可运动的最大距离为10
@Override
protected void onDraw(Canvas canvas) {
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(2);
//创建一条路径
Path path=new Path();
path.lineTo(100,260);
path.lineTo(125,60);
path.lineTo(200,180);
path.lineTo(250,90);
path.lineTo(320,200);
path.lineTo(400,20);
path.lineTo(499,160);
mPaint.setPathEffect(new DiscretePathEffect(1,0));
canvas.drawPath(path,mPaint);
canvas.translate(0,200);
mPaint.setPathEffect(null);//清除画笔的路径效果
mPaint.setColor(Color.RED);
canvas.drawPath(path,mPaint);
mPaint.setPathEffect(new DiscretePathEffect(1,10));
mPaint.setColor(Color.WHITE);
canvas.drawPath(path,mPaint);
canvas.translate(0,200);
mPaint.setPathEffect(null);//清除画笔的路径效果
mPaint.setColor(Color.RED);
canvas.drawPath(path,mPaint);
mPaint.setPathEffect(new DiscretePathEffect(10,20));
mPaint.setColor(Color.WHITE);
canvas.drawPath(path,mPaint);
}
可以看到DiscretePathEffect(1,0)的效果,跟本身直线路径没区别,因为按照上面定义的理解,每个像素都做离散运动,运动距离为0,不就等于这个点没有运动吗,所以还是直线。
我们可以通过Paint.setPathEffect(null)来清除画笔的路径效果