Android实现自定义view实现图表功能
2018-06-15 本文已影响0人
落后程序员
简单实现了一个自定义view,仅供学习用
效果图:
image.png
package org.mo.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Build;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class LineChartView extends View {
private final static String TAG = "LineChartView";
private Map<String, Integer> data = null;
private List<Integer> yList = null;
private List<String> xList = null;
private Paint yPaint = null;
private Paint xPaint = null;
private Paint linePaint = null;
private Paint pathPaint = null;
private Paint normalWhilePointPaint = null;
private Paint normalPointPaint = null;
private Paint clickPointPaint = null;
private Path path;
private int w, h;
private int yStartPoint;
private int yStartTPoint;
private int xLeftPadding;
private int xCircleLeftPadding;
private int xStartPoint;
private int radius;
private int radiusCenter;
public LineChartView(Context context) {
super(context);
initData();
}
public LineChartView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initData();
}
public LineChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initData();
}
private void initData() {
yPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
yPaint.setColor(Color.parseColor("#999999"));
yPaint.setTextSize(dip2px(getContext(), 18));
yPaint.setTextAlign(Paint.Align.LEFT);
xPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
xPaint.setColor(Color.parseColor("#999999"));
xPaint.setTextSize(dip2px(getContext(), 18));
linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
linePaint.setColor(Color.parseColor("#999999"));
linePaint.setTextSize(dip2px(getContext(), 20));
normalPointPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
normalPointPaint.setColor(Color.parseColor("#303F9F"));
normalPointPaint.setStrokeWidth(dip2px(getContext(), 3));
normalPointPaint.setStyle(Paint.Style.STROKE);
normalWhilePointPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
normalWhilePointPaint.setColor(Color.parseColor("#FFFFFF"));
normalWhilePointPaint.setStrokeWidth(dip2px(getContext(), 3));
normalWhilePointPaint.setStyle(Paint.Style.FILL);
pathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
pathPaint.setColor(Color.parseColor("#303F9F"));
pathPaint.setStrokeWidth(dip2px(getContext(), 3));
pathPaint.setStyle(Paint.Style.STROKE);
path = new Path();
yList = new ArrayList<>();
yList.add(0);
yList.add(50);
yList.add(100);
yList.add(150);
yList.add(200);
xList = new ArrayList<>();
xList.add("5-22");
xList.add("5-23");
xList.add("5-24");
xList.add("5-25");
xList.add("5-26");
xList.add("5-27");
xList.add("5-28");
data = new HashMap<>();
data.put("5-22", 47);
data.put("5-23", 120);
data.put("5-24", 90);
data.put("5-25", 60);
data.put("5-26", 80);
data.put("5-27", 50);
data.put("5-28", 100);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
//View从API Level 11才加入setLayerType方法
//关闭硬件加速
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
yStartPoint = dip2px(getContext(), 30);//y轴的起点位置
yStartTPoint = dip2px(getContext(), 25);//y轴的起点位置
xLeftPadding = dip2px(getContext(), 10);//y离x的距离
xCircleLeftPadding = dip2px(getContext(), 16);//圆的偏差值
xStartPoint = dip2px(getContext(), 55); //x轴的起点位置
radius = dip2px(getContext(), 6);//圆半径
radiusCenter = radius - dip2px(getContext(), 1);//圆半径
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
w = getWidth();
h = getHeight();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int ySize = yList.size();
int xSize = xList.size();
float yProp = h / ySize;
Log.i(TAG, "yProp:" + yProp);
float xFair = (w - xStartPoint) / xSize;
for (int i = 0; i < ySize; i++) {
//纵坐标
float startTextY = yProp * (ySize - i) - yStartTPoint;
float startLineY = yProp * (ySize - i) - yStartPoint;
Log.i(TAG, "startTextY:" + startTextY);
String yName = String.valueOf(yList.get(i));
canvas.drawText(yName, xLeftPadding, startTextY, yPaint);
//画对应的线
canvas.drawLine(xStartPoint, startLineY, w - xLeftPadding, startLineY, linePaint);
}
float yUnit = yProp / 50f;
Log.i(TAG, "yUnit:" + yUnit);
List<Float> circleXs = new ArrayList<>();
List<Float> circleYs = new ArrayList<>();
for (int i = 0; i < xSize; i++) {
//横坐标
String xName = String.valueOf(xList.get(i));
canvas.drawText(xName, xStartPoint + xFair * i, h, xPaint);
Integer integer = data.get(xList.get(i));
Log.i(TAG, "integer:" + integer);
float circleX = xStartPoint + xCircleLeftPadding + xFair * i;
float circleY = h - (yUnit * integer) - yStartPoint;
Log.i(TAG, "circleX:" + circleX);
Log.i(TAG, "cicrleY:" + circleY);
circleXs.add(circleX);
circleYs.add(circleY);
}
path.moveTo(circleXs.get(0), circleYs.get(0));
for (int i = 0; i < circleXs.size() - 1; i++) {
Float currentX = circleXs.get(i);
Float currentY = circleYs.get(i);
Float nextX = circleXs.get(i + 1);
Float nextY = circleYs.get(i + 1);
int compare = Float.compare(nextY, currentY);
float y1 = 0;
float y2 = 0;
if (compare > 0) {
y1 = nextY + yStartTPoint;
y2 = nextY + yStartPoint;
} else {
y1 = h - currentY - yStartTPoint;
y2 = h - currentY - yStartPoint;
}
//这里最好分化为每小时的进度,不然不好绘制,╮(╯﹏╰)╭
//path.cubicTo(currentX + (nextX - currentX) / 4, y1, currentX + (nextX - currentX) * 3 / 4, y2, nextX, nextY);
path.cubicTo(currentX, currentY, currentX + (nextX - currentX) / 2, currentY - (nextY - currentY) / 2, nextX, nextY);
}
canvas.drawPath(path, pathPaint);
for (int i = 0; i < circleXs.size(); i++) {
//normalPointPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
canvas.drawCircle(circleXs.get(i), circleYs.get(i), radius, normalPointPaint);
canvas.drawCircle(circleXs.get(i), circleYs.get(i), radiusCenter, normalWhilePointPaint);//用于消除交际部分,我菜只能这样做了
}
}
/**
* 将dp转换成px
*
* @param context
* @param dpValue
* @return
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 将像素转换成dp
*
* @param context
* @param pxValue
* @return
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
}