自定义折线、曲线图,性能一般,还没来得及优化,需要用的可以拿去试一下:
package com.zz.kotlintest.view; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Point; import android.os.Build; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; import com.zz.kotlintest.R; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * @Author xifangzheng * Created by zz on 2017/9/13 17:32. * class explain: 曲线 折线分布图 * update: upAuthor: explain: */ public class LineGraphicView extends View {/** * 公共部分 */ private static final int CIRCLE_SIZE = 6; // 圆点的直径 private boolean isDrawCirclePoints = true; //是否画每个圆点 private ArrayList<ArrayList<Double>> yRawDataLineList; // TODO 自己新增 线的集合 private ArrayList<Paint> paintList; private float pointSpace; // 两个点之间的 x 轴间距 private ArrayList<String> showAlertTextList; private ArrayList<Boolean> isShowBottomRawDatas; private ArrayList<Boolean> isShowTopTextIndexList; private boolean clearView; private String clearAfterShowText = "暂无数据"; public static enum Linestyle { Line, //折线 Curve; //曲线 } private Context mContext; private Paint mPaint; private Resources res; private DisplayMetrics dm; /** * data */ private Linestyle mStyle = Linestyle.Line; public void setStyle(Linestyle mStyle) { this.mStyle = mStyle; } private int canvasHeight; private int canvasWidth; private int bheight = 0; // 表的高度 private int bwidth = 0; // 表的宽度 private int blwidh; // 表的左右边距 private boolean isMeasure = true; /** * Y轴最大值 */ private float maxValue; /** * Y轴间距值 */ private float averageValue; private int marginTop = 40; private int marginBottom = 20; int bottomTextVerticalSpacing = 4; int bottomTextHeight = 24; // 这个可让画布增加底部文字的高度 /** * 曲线上总点数 */ private Point[] mPoints; private ArrayList<Point[]> mPointsLineList; // TODO 新增用来存放所有线的点的集合 /** * 纵坐标值 */ private ArrayList<Double> yRawData; /** * 横坐标值 */ private ArrayList<String> xRawDatas; private ArrayList<Integer> xList = new ArrayList<Integer>();// 记录每个x的值 private ArrayList<ArrayList<Float>> xListLineList = new ArrayList<>();// 记录每个x的值 // TODO 新增 private float spacingHeight; public boolean isDrawCirclePoints() { return isDrawCirclePoints; } public void setDrawCirclePoints(boolean drawCirclePoints) { isDrawCirclePoints = drawCirclePoints; } public LineGraphicView(Context context) { this(context, null); } public LineGraphicView(Context context, AttributeSet attrs) { super(context, attrs); this.mContext = context; initView(); } private void initView() { this.res = mContext.getResources(); this.mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setAntiAlias(true); dm = new DisplayMetrics(); WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); wm.getDefaultDisplay().getMetrics(dm); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { if (isMeasure) { // this.canvasHeight = getHeight(); // 高度 this.canvasHeight = getHeight() - dip2px(bottomTextHeight) - dip2px(bottomTextVerticalSpacing); // 减的bottomTextHeight是文字的高度 this.canvasWidth = getWidth(); if (bheight == 0) { bheight = (int) (canvasHeight - marginBottom); } blwidh = dip2px(19); this.bwidth = canvasWidth - blwidh * 2; isMeasure = false; // pointSpace = (canvasWidth - blwidh * 2) / (xRawDatas.size() - 1); } if (xRawDatas == null) { return; } pointSpace = (canvasWidth - blwidh * 2) / (xRawDatas.size() - 1); // Log.e("onSizeChanged打印:", "pointSpace:" + pointSpace + " canvasWidth:" + canvasWidth + " blwidh:" + blwidh + " bwidth:" + bwidth); } @Override protected void onDraw(Canvas canvas) { if (clearView) { mPaint.setColor(res.getColor(R.color.color_DefaultDrawLine)); mPaint.setStrokeWidth(dip2px(0)); mPaint.setTextSize(dip2px(15)); mPaint.setStyle(Paint.Style.STROKE); mPaint.setFlags(Gravity.CENTER_HORIZONTAL); canvas.drawText(clearAfterShowText, bwidth / 2 + blwidh - 2 * mPaint.getTextSize(), bheight / 2, mPaint); return; } mPaint.setColor(res.getColor(R.color.color_DefaultDrawLine)); mPaint.setStrokeWidth(dip2px(1)); mPaint.setStyle(Paint.Style.STROKE); if (yRawDataLineList == null) { return; } drawAllXLine(canvas); // 画直线(纵向) // drawAllYLine(canvas); drawAllYLineList(canvas); // 点的操作设置 // mPoints = getPoints(); // 新增 mPointsLineList = getPointsLineList(); // mPaint.setPathEffect(new DashPathEffect(new float[]{20, 20}, 0)); if (mStyle == Linestyle.Curve) { // drawScrollLine(canvas); drawScrollLineList(canvas); } else { // drawLine(canvas); drawLineList(canvas); } mPaint.setStyle(Paint.Style.FILL); if (isDrawCirclePoints) { drawCirclePoints(canvas); } if (isShowVerticalLine) { mPaint.setStrokeWidth(2); mPaint.setTextSize(dip2px(16)); mPaint.setColor(res.getColor(R.color.color_DefaultMoveLine)); // canvas.drawLine(currentTounchX, marginTop, currentTounchX, canvasHeight, mPaint); if (isCanShowMoveLineTopText) { drawText(moveLineTopText, currentTounchX, marginTop - dip2px(moveLineTopTextSpace), canvas, R.color.color_DefaultCoverRoundText, true, moveLineTopTextTextSize); } canvas.drawLine(currentTounchX, marginTop, currentTounchX, bheight + marginTop, mPaint); if (isShowCoverRound) { if (isShowLineRight) { int rightAddWidth = 0; int maxLengthIndex = 0; int maxLength = 0; for (int i = 0; i < showAlertTextValuesList.size(); i++) { float textNum = Float.valueOf(showAlertTextValuesList.get(i)); String textValue = (textNum == Math.round(textNum) ? String.valueOf(Math.round(textNum)) : String.valueOf(textNum)); if (textValue.length() >= maxLength) { maxLengthIndex = i; maxLength = textValue.length(); } } if (maxLength >= valueLength) { float textNum = Float.valueOf(showAlertTextValuesList.get(maxLengthIndex)); String textValue = (textNum == Math.round(textNum) ? String.valueOf(Math.round(textNum)) : String.valueOf(textNum)); rightAddWidth = (textValue.contains(".") ? dip2px(pointAddWidth) : 0) + (textValue.replace(".", "").length() - valueLength) * dip2px(everyAddWidth); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { mPaint.setColor(res.getColor(R.color.colorWhite)); mPaint.setStyle(Paint.Style.FILL); canvas.drawRoundRect(currentTounchX + dip2px(coverRoundMarginLeft), dip2px(coverRoundMarginTop), currentTounchX + dip2px(coverRoundWidth) + dip2px(coverRoundMarginLeft) + rightAddWidth, dip2px(coverRoundMarginTop + coverRoundTextMarginTop * (2) + 2 + coverRoundTextVerticalSpacing * (showAlertTextList.size() - 1) + coverRoundTextSize * showAlertTextList.size()), coverRoundRadius, coverRoundRadius, mPaint); mPaint.setColor(res.getColor(R.color.color_cccccc)); mPaint.setStyle(Paint.Style.STROKE); canvas.drawRoundRect(currentTounchX + dip2px(coverRoundMarginLeft + 1), dip2px(coverRoundMarginTop + 1), currentTounchX + dip2px(coverRoundWidth) + dip2px(coverRoundMarginLeft) + rightAddWidth, dip2px(coverRoundMarginTop + coverRoundTextMarginTop * (2) + 2 + coverRoundTextVerticalSpacing * (showAlertTextList.size() - 1) + coverRoundTextSize * showAlertTextList.size()), coverRoundRadius, coverRoundRadius, mPaint); } if (showAlertTextList != null && showAlertTextList.size() > 0) { mPaint.setColor(res.getColor(R.color.color_DefaultCoverRoundText)); mPaint.setTextSize(dip2px(coverRoundTextSize)); mPaint.setStyle(Paint.Style.FILL); mPaint.setTextAlign(Paint.Align.LEFT); for (int i = 0; i < showAlertTextList.size(); i++) { float textNum = Float.valueOf(showAlertTextValuesList.get(i)); String textValue = (textNum == Math.round(textNum) ? String.valueOf(Math.round(textNum)) : String.valueOf