自定义 View ———— 折线图(重写 onDraw方法)
程序员文章站
2022-03-11 11:05:49
...
实现一个如下效果的折线图
这样的效果实现的方式很容易想到的就是重写 onDraw 方法,给定一组 float 值,分别画点、线,那么下面有颜色的阴影部分是用什么画呢,就用到了 Path, 一个点一个点相连成一个封闭的图形,便可画出这个图形。如果先画点,再画阴影部分,是会把点遮住一部分的,所以实现的时候先画完了阴影部分,再画线和点。不过这样子在 onDraw 方法里就有两个 for 循环,如果有好的办法欢迎提出。
下面直接贴出 View 的整个代码,代码不多
/**
* @author hexiaosa
* @date 2018/8/15
*/
public class CustomLineChart extends View {
private int width; // 宽
private int height; // 高
private int pointNum; // 折点个数
private int lineColor; // 折线颜色
private int shadowColor; // 阴影颜色
private float[] percents; // 百分比,可以理解为任务完成百分比
private int itemWidth;
private Path path; // 避免在 onDraw 方法内创建多个对象,所以在这里声明一个成员变量
public CustomLineChart(Context context) {
this(context, null);
}
public CustomLineChart(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomLineChart(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 线颜色,阴影颜色,折点个数
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomLineChart);
lineColor = typedArray.getColor(R.styleable.CustomLineChart_lineColor, Color.BLACK);
shadowColor = typedArray.getColor(R.styleable.CustomLineChart_shadowColor, Color.BLACK);
pointNum = typedArray.getInteger(R.styleable.CustomLineChart_pointNum, 0);
}
@Override
protected void onDraw(Canvas canvas) {
if (pointNum == 0) {
return;
}
if (percents == null || percents.length != pointNum) {
return;
}
if (width == 0) {
width = getMeasuredWidth();
}
if (height == 0) {
height = getMeasuredHeight();
}
if (path == null) {
path = new Path();
}
itemWidth = width/(pointNum-1);
Paint paint = new Paint();
paint.setStrokeWidth(5);
// 阴影部分使用 Path 连接成一个封闭图形
path.reset();
path.moveTo(0, height);
path.lineTo(0, height*(1-percents[0]));
for (int i = 1; i < percents.length; i++) {
// 连接阴影
path.lineTo(itemWidth*i, height*(1-percents[i]));
}
path.lineTo(width, height);
path.lineTo(0, height);
paint.setColor(shadowColor);
// 画阴影
canvas.drawPath(path, paint);
path.close();
paint.setColor(lineColor);
canvas.drawCircle(0, height*(1-percents[0]), 10, paint);
for (int i = 1; i < percents.length; i++) {
// 画线
canvas.drawLine(itemWidth*(i-1), height*(1-percents[i-1]), itemWidth*i, height*(1-percents[i]), paint);
// 画点
canvas.drawCircle(itemWidth*i, height*(1-percents[i]), 10, paint);
}
canvas.save();
}
public void setPercents(float[] percents) {
this.percents = percents;
invalidate();
}
public void setLineColor(int lineColor) {
this.lineColor = lineColor;
}
public void setShadowColor(int shadowColor) {
this.shadowColor = shadowColor;
}
public void setPointNum(int pointNum) {
this.pointNum = pointNum;
}
}
// attr.xml:
<declare-styleable name="CustomLineChart">
<attr name="lineColor" format="color"/>
<attr name="shadowColor" format="color"/>
<attr name="pointNum" format="integer"/>
</declare-styleable>
使用示例:
CustomLineChart clc = (CustomLineChart) findViewById(R.id.clc);
// 必须设置,还有 pointNum 在布局或代码设置至少有一个地方设置,且 pointNum 需等于 percents.length
clc.setPercents(new float[]{0.5f, 0.3f, 0.4f, 0.7f, 0.1f, 0.2f, 0.6f, 0.8f, 0.9f, 1f});