通过这个view大致了解了几个方法,可通过PathEffect给path设置样式;
大致分三步:
第一步:通过canvas.drawArc()方法先把圆弧画出来
第二步:画刻度(这里通过给画笔设置PathEffect的方法实现刻度绘制,并非for循环画线)
第三步:画指针(这里需要了解正弦余弦,其实都是API的方法,直接调用即可,但需要自己理解)
public class DashboardView extends View {
// 画笔
Paint mPaint;
// 画刻度使用
Path dashPath;
// path效果 比DashPathEffect 多一个前缀Path ,可理解为使用一个Path 来绘制
PathDashPathEffect effect;
// 圆弧半径
private float mRadius = UnitUtil.dp2px(120);
// 未封口的角度
private int remainAngle = 100;
// 指针长度
private float pointerLength = UnitUtil.dp2px(90);
// 刻度数量
private int scaleCount = 16;
// 指针指向的刻度
private int mAngle = 10;
public DashboardView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
// 此模块代码会给随构造函数super()后执行
{
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.parseColor("#228fba"));
// 2dp,在view中进行绘制时直接使用2是像素,所以需要用工具类将2dp转为对应的像素值
mPaint.setStrokeWidth(UnitUtil.dp2px(2));
mPaint.setStyle(Paint.Style.STROKE);
/*--------------------------下面内容第二步画刻度时使用-------------------------------*/
// 刻度使用path,这个算是一个小刻度 给PathDashPathEffect使用
dashPath = new Path();
dashPath.addRect(
0, 0,
UnitUtil.dp2px(2), UnitUtil.dp2px(8),
Path.Direction.CW // CW 顺时针 CCW逆时针
);
// 创建弧度的path,然后使用PathMeasure测量这个圆弧的长度
Path arcPath = new Path();
arcPath.addArc(
getWidth() / 2 - mRadius, getHeight() / 2 - mRadius,
getWidth() / 2 + mRadius, getHeight() / 2 + mRadius,
90 + remainAngle / 2,
360 - remainAngle
);
// 测量圆弧长度
PathMeasure pathMeasure = new PathMeasure(arcPath, false);
effect = new PathDashPathEffect(
// 用来绘制的path
dashPath,
// 两个相邻的path起点之间的间隔,如果不减去一个刻度宽的话,最后一个会画在紧按着圆弧的尾部,而不在圆弧上面
(pathMeasure.getLength() - UnitUtil.dp2px(2)) / (scaleCount - 1),
// 虚线的偏移
0,
// 旋转 一共三个值:TRANSLATE位移,MORPH变体
PathDashPathEffect.Style.ROTATE
);
}
@SuppressLint("NewApi")
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 第一步:绘制弧线(没有封口的圆)
canvas.drawArc(
// 前四个参数是矩形的左上角右下角,给一个矩形范围,也就是圆的绘制范围
getWidth() / 2 - mRadius, getHeight() / 2 - mRadius,
getWidth() / 2 + mRadius, getHeight() / 2 + mRadius,
90 + remainAngle / 2, // 开始角度
360 - remainAngle, // 结束角度
false, // 是否闭合
mPaint
);
// 第二步:绘制刻度
mPaint.setPathEffect(effect);
canvas.drawArc(
getWidth() / 2 - mRadius, getHeight() / 2 - mRadius,
getWidth() / 2 + mRadius, getHeight() / 2 + mRadius,
90 + remainAngle / 2,
360 - remainAngle,
false,
mPaint
);
// 使用完之后恢复
mPaint.setPathEffect(null);
/*
第三步:画指针
Math.toRadians(将角度转换为弧度)
cos 余弦
sin 正弦
最后再乘以斜边(pointerLength) 可得到邻边,对边长度
*/
canvas.drawLine(getWidth() / 2, getHeight() / 2,
(float) Math.cos(Math.toRadians(getAngleFromMark(mAngle))) * pointerLength + getWidth() / 2,
(float) Math.sin(Math.toRadians(getAngleFromMark(mAngle))) * pointerLength + getHeight() / 2,
mPaint);
}
private int getAngleFromMark(int mark) {
// 90°+ 下面剩余角度一半 + 刻度角度
return (int) (90 + (float) remainAngle / 2 + (360 - (float) remainAngle) / (scaleCount - 1) * mark);
}
}
两个点需要理解:①通过PathEffect绘制刻度 ②通过正弦余弦获取指针坐标点
相比上面仪表盘,饼图只需理解通过正弦余弦获取偏移点坐标即可
/**
* 饼图
*/
public class PieView extends View {
Paint mPaint;
// 给一个范围
RectF mRectF = new RectF();
// 饼图各个区域的角度
int[] angles = {60, 100, 120, 80};
// 饼图颜色
int[] colors = {Color.parseColor("#2979FF"), Color.parseColor("#C2185B"),
Color.parseColor("#009688"), Color.parseColor("#FF8F00")};
private int RADIUS = (int) UnitUtil.dp2px(150);
// 偏移量
private int gapLength = (int) UnitUtil.dp2px(5);
public PieView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
{
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
// 当视图的大小发生更改时,将调用此方法
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mRectF.set(
getWidth() / 2 - RADIUS, getHeight() / 2 - RADIUS,
getWidth() / 2 + RADIUS, getHeight() / 2 + RADIUS
);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int currentAngle = 0;
for (int i = 0; i < angles.length; i++) {
// 不同区域设置不同颜色
mPaint.setColor(colors[i]);
// 当需要平移画布时,先保存画布,然后平移,画完之后恢复画布位置,不影响下一次绘制
canvas.save();
if (i == 2) {
/*
将画布平移
Math.toRadians(将角度转换为弧度),然后通过余弦,正弦获取x,y坐标点
*/
canvas.translate(
(float) Math.cos(Math.toRadians(currentAngle + angles[i] / 2)) * gapLength,
(float) Math.sin(Math.toRadians(currentAngle + angles[i] / 2)) * gapLength
);
}
canvas.drawArc(
mRectF,
currentAngle,
angles[i],
true,
mPaint
);
canvas.restore();
currentAngle += angles[i];
}
}
}