自定义View-Canvas之绘制图形

参考文档:

1.http://www.gcssloop.com/customview/CustomViewIndex 作者:GcsSloop

相关知识点,在GcsSloop的自定义view系列都有说到,我这里摘录了一些自己感兴趣的知识点,也可以直接参考GcsSloop的自定义view系列。


在这里,主要是讲一下自定义view的流程,以及一个简单的demo。

自定义view的分类和流程

自定义view的分类:

自定义view的流程:

下面,编写的一个简单的demo,也是根据这个流程来的。

demo是一个自定义饼状图。

我们先来看看Canvas的常用操作:

以及对画布的常用操作:

现在,我们开始制作饼状图。

在展示百分比数据的时候经常会用到饼状图,比如这样:

简单分析:

分析饼状图的构成,非常明显,饼状图就是一个又一个扇形构成的,每个扇形都有不同的颜色,对应有名字,数据和百分比。

经过上面分析可以得出饼状图的基本数据应包括:名字 百分比 数据值 对应的颜色 角度。

用户关心的数据:名字 百分比 数据值

需要程序计算的数据:百分比 对应的角度

其中颜色一项,可以使用户指定,或者程序指定(我们这里使用程序指定)

封装数据:

public class PieData {
    // 用户关心数据
    private String name;// 名字
    private float value;// 数值
    private float percentage; // 百分比
    // 非用户关心数据
    private int color = 0; // 颜色
    private float angle = 0; // 角度

    public PieData(@NonNull String name, @NonNull float value) {
        this.name = name;
        this.value = value;
    }
}
PS:以上省略了get  set方法

自定义view:

先按照自定义view的流程梳理一遍(确定每个步骤应该做的事情):

代码如下:

package com.rick.pieview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import java.util.ArrayList;

/**
 * Created by MyPC on 2017/5/11.
 */

public class PieView extends View {
    // 颜色表 (注意: 此处定义颜色使用的是ARGB,带Alpha通道的)
    private int[] mColors = {0xFFCCFF00, 0xFF6495ED, 0xFFE32636, 0xFF800000, 0xFF808000, 0xFFFF8C69, 0xFF808080,
            0xFFE6B800, 0xFF7CFC00};
    // 饼状图初始绘制角度
    private float mStartAngle = 0;
    private ArrayList<PieData> mData;
    private int mWidth, mHeight;
    private Paint mPaint = new Paint();

    //文字色块部分
    private PointF mStartPoint = new PointF(20, 20);
    private PointF mCurrentPoint = new PointF(mStartPoint.x, mStartPoint.y);
    private float mColorRectSideLength = 20;
    private float mTextInterval = 10;
    private float mRowMaxLength;


    public PieView(Context context) {
        this(context, null);
    }

    public PieView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        initPaint();
    }

    private void initPaint() {
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (null == mData || mData.size() <= 0) {
            return;
        }
        float currentStartAngle = mStartAngle;                          // 当前起始角度
        canvas.translate(mWidth / 2, mHeight / 2);                      // 将画布坐标原点移动到中心位置
        float r = (float) (Math.min(mWidth, mHeight) / 2 * 0.8);        // 饼状图半径
        RectF rectF = new RectF(-r, -r, r, r);                          // 饼状图绘制区域

        for (int i = 0; i < mData.size(); i++) {
            PieData pie = mData.get(i);
            mPaint.setColor(pie.getColor());
            canvas.drawArc(rectF, currentStartAngle, pie.getAngle(), true, mPaint);

            canvas.save();
            canvas.rotate(currentStartAngle + (pie.getAngle() / 2));
//            canvas.translate(mWidth / 8, mHeight / 8);
//            RectF colorRect = new RectF(mCurrentPoint.x, mCurrentPoint.y, mCurrentPoint.x + mColorRectSideLength, mCurrentPoint.y + mColorRectSideLength);
//            Path path = new Path();
//            path.addRect(colorRect, Path.Direction.CCW);
            mPaint.setColor(Color.BLACK);
//            canvas.drawTextOnPath(pie.getName(), path, 0, 0, mPaint);
            mPaint.setTextSize(20);
            canvas.drawText(pie.getName(), 0, 0, mPaint);
            canvas.restore();

            currentStartAngle += pie.getAngle();
        }

    }

    // 设置起始角度
    public void setmStartAngle(float mStartAngle) {
        this.mStartAngle = mStartAngle;
        invalidate();
    }

    // 设置数据
    public void setData(ArrayList<PieData> pieDatas) {
        this.mData = pieDatas;
        initData();
        invalidate();
    }

    // 初始化数据
    private void initData() {
        if (null == mData || mData.size() <= 0) {
            return;
        }

        //计算数值和    设置颜色
        float sumValue = 0;
        for (int i = 0; i < mData.size(); i++) {
            PieData pie = mData.get(i);

            sumValue += pie.getValue();
            pie.setColor(mColors[i % mColors.length]);
        }

        for (int i = 0; i < mData.size(); i++) {
            PieData pie = mData.get(i);

            float percentage = pie.getValue() / sumValue; // 百分比
            float angle = percentage * 360; //对应的角度

            pie.setPercentage(percentage);
            pie.setAngle(angle);


            Log.i("angle", "" + pie.getAngle());
        }

    }
}
PS:在更改了数据需要重绘界面时调用invalidate()这个函数重新绘制。
效果图

总结:

感觉自己在自定义view方面,有点薄弱,但是跟着自定义view的流程一步步走,动手敲代码,其实都还是挺容易的。

在这里,感谢GcsSloop。













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值