Android 自定义View----PathEffect(仪表盘,饼图)

通过这个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];
        }

    }

}

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值