Android自定义View实现简单的折线图、柱状图
2017-04-21 15:03
323 查看
首先说第一个柱状图,实现很简单。一个自定义View,重现里面的OnDraw方法。然后利用paint,canvas绘制带填充的长方形即可。每个长方形的X轴平方View的x轴即可,长方形的高度通过简单的计算即可得到。下面上柱状图代码
package com.hrules.charter.demo.widget;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.BounceInterpolator;
import com.hrules.charter.demo.R;
import java.util.Random;
/**
* 柱状图
* Created by 黄海 on 2017/4/17.
*/
public class Histogram extends View implements View.OnClickListener {
int width, height;
Paint paintBar, paintText;
float[] values = new float[15];
float[] valuesTemp = new float[15];
int colorBackground = R.color.default_barBackgroundColor;//柱状背景
int[] colorBar = new int[]{R.color.lightBlue500, R.color.lightBlue400, R.color.lightBlue300};//柱状颜色
float maxY;
int barMarginLeft = 7;
int tagHeight = 45;//x和Y轴的数字
boolean anim;
boolean showLineXNums = true, showLineYNums = true;//展示X、Y轴的数字
int lineYNums = 5;//Y轴展示的格数
ValueAnimator valueAnimator;
public Histogram(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public Histogram(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paintText = paintBar = new Paint();
paintBar.setAntiAlias(true);
paintText.setAntiAlias(true);
paintText.setTextSize(25);
paintText.setColor(getResources().getColor(colorBar[0]));
initValuesAndMaxY();
setOnClickListener(this);
}
private void initValuesAndMaxY() {
Random random = new Random();
for (int i = 0; i < values.length; i++) {
values[i] = random.nextFloat() * 100;
}
for (float i : values) {
maxY = maxY < i ? i : maxY;
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
width = getMeasuredWidth();
height = getMeasuredHeight();
int barWidth = (width - tagHeight) / values.length;
int j = 0;
if (!anim)
valuesTemp = values.clone();
for (int i = 0; i < valuesTemp.length; i++) {
RectF rect = new RectF();
rect.left = tagHeight + i * barWidth + barMarginLeft;
rect.top = (height - tagHeight) * (1 - 1.0f * valuesTemp[i] / maxY);
rect.right = rect.left + barWidth - barMarginLeft;
rect.bottom = height - tagHeight;
//draw the barBackground
paintBar.setColor(getResources().getColor(colorBackground));
canvas.drawRect(rect.left, 0, rect.right, rect.bottom, paintBar);
//paint the bar
j = j > colorBar.length - 1 ? 0 : j;
paintBar.setColor(getResources().getColor(colorBar[j++]));
canvas.drawRect(rect, paintBar);
if (showLineXNums) {
//draw x-coordinate num
float textWidth = paintText.measureText(String.valueOf(i));
float textLeft = rect.left + rect.width() / 2 - textWidth / 2;
canvas.drawText(String.valueOf(i), textLeft, height, paintText);
}
}
//draw y-coordinate num
if (showLineYNums) {
int avgHeight = (height - tagHeight) / lineYNums;
for (int i = 0; i < lineYNums; i++) {
float x = 0;
float y = (height - tagHeight) - avgHeight * (i + 1);
int valueY = (int) (maxY * (i + 1) / lineYNums);
// canvas写字是从x、y轴往右上写的
canvas.drawText(String.valueOf(valueY), x, y + 30, paintText);
}
}
}
@Override
public void onClick(View v) {
anim = true;
valueAnimator = ValueAnimator.ofFloat(0f, 1f);
valuesTemp = values.clone();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
for (int i = 0; i < valuesTemp.length; i++) {
//update valuesTemps
float animatedValue = (float) animation.getAnimatedValue();
valuesTemp[i] = maxY * animatedValue < values[i] ? maxY * animatedValue : values[i];
}
invalidate();
}
});
// valueAnimator.setInterpolator(new LinearInterpolator());
//落地回调效果
valueAnimator.setInterpolator(new BounceInterpolator());
valueAnimator.setDuration(2000l);
valueAnimator.start();
}
}
实现比较简单,注释都有。最后说下onClick方法的作用:valuesTemp是原有柱状数据的副本,view点击后让valuesTemp的每个数据从maxY的最小百分比开始不断的增长,从而实现一个动态改变的动画效果,如下:
折线图运用的paint,canvas与path完成,计算每个点的位置和柱状图类似,折线图形成一个填充效果也简单就是path close一下,然后绘制close后的path就是。下面看源码
package com.hrules.charter.demo.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import com.hrules.charter.demo.R;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* 折线图
* Created by 黄海 on 2017/4/18.
*/
public class LineChart extends View {
Path path = new Path();
float[] values = new float[15];
float maxY;
Paint paintXy, paintLine;
int width, height;//view 宽高
public LineChart(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public LineChart(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initValuesAndMaxY();
paintXy = new Paint(Paint.ANTI_ALIAS_FLAG);
paintXy.setStyle(Paint.Style.STROKE);
paintXy.setStrokeWidth(6);
paintXy.setColor(getResources().getColor(R.color.lightBlue500));
paintLine = new Paint(Paint.ANTI_ALIAS_FLAG);
paintLine.setStyle(Paint.Style.FILL);
paintLine.setColor(getResources().getColor(R.color.colorPrimary));
}
private void initValuesAndMaxY() {
Random random = new Random();
for (int i = 0; i < values.length; i++) {
values[i] = random.nextFloat() * 100;
maxY = maxY < values[i] ? values[i] : maxY;
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
width = getMeasuredWidth();
height = getMeasuredHeight();
//每格宽度
int widthAvg = width / values.length;
//画x轴y轴
path.moveTo(0, 0);
path.lineTo(0, height);
path.lineTo(width, height);
canvas.drawPath(path, paintXy);
List<PointF> list = new ArrayList<>();
for (int i = 0; i < values.length; i++) {//收集坐标信息
PointF point = new PointF(widthAvg / 2 + i * widthAvg, 0);
point.set(widthAvg / 2 + i * widthAvg, (1 - values[i] / maxY) * height);
list.add(point);
}
//画线
path.reset();//清除 画x轴y轴而产生的闭合影响
path.moveTo(list.get(0).x, list.get(0).y);
for (int i = 1; i < values.length; i++) {
path.lineTo(list.get(i).x, list.get(i).y);
// path.cubicTo(ps.x, ps.y,(ps.x+pe.x)/2,(ps.y+pe.y)/2, pe.x, pe.y);//画三次贝塞尔曲线
}
canvas.drawPath(path, paintXy);
//折线图闭合
path.lineTo(list.get(values.length - 1).x, height);
path.lineTo(list.get(0).x, height);
path.close();
canvas.drawPath(path, paintLine);
//画点
for (int i = 0; i < values.length; i++) {
canvas.drawCircle(list.get(i).x, list.get(i).y, 9, paintLine);
}
}
}
相关文章推荐
- android之自定义View和ViewGroup(六)(代码篇,实现简单的走势图,柱状图同理)
- Android自定义View 简单实现多图片选择控件
- android 自定义view 实现简单贪吃蛇
- Android简单自定义view的实现
- Android利用自定义View实现简单的足球战术板
- Android自定义View实现折线图效果
- Android自定义view实现动态柱状图
- Android高阶自定义ChartView,让你几分钟掌握绘制,折线图,曲线图,柱状图,柱线图,分分钟写图表框架
- Android 实现一个简单的自定义View
- Android自定义ViewGroup:实现简单的垂直方向线性布局(2)
- 自定义View很简单 - Android翻页效果原理实现之引入折线
- [AndroidUI]自定义view(五):实现动态柱状图
- Android自定义View---掌上英雄联盟能力分析简单实现
- Android 一个简单的自定义WheelView实现
- Android自定义View 简单实现多图片选择控件
- Android自定义View----时钟/仪表盘的简单实现
- [Android开发] 自定义View之重写View非常简单实现开关按钮SwitchView
- Android自定义View——简单实现边缘凹凸电子票效果
- Android开发自定义View的简单实现
- Android简单实现自定义View