参考文档:
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。