Android 饼状图,和 柱状图 ,自定义控件

你的打赏,是对我最大的支持:

 

 

饼状图效果图:

Android 饼状图,和 柱状图 ,自定义控件_第1张图片

 

红色代表核心 

 

布局XMl :

 




    

        

        

        

        

        

        

        


    

 

饼状图代码:

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

import java.util.Random;

/**
 * 

* Description:折线数据类型饼状统计图 *

* * @author tangzhijie */ public class LinePieView extends View { //使用wrap_content时默认的尺寸 public static final int DEFAULT_WIDTH = 600; public static final int DEFAULT_HEIGHT = 600; /** * 斜线长度 */ private static final int SlASH_LINE_OFFSET = 50; /** * 横线长度 */ private static final int HOR_LINE_LENGTH = 100; /** * 横线上文字的横向偏移量 */ private static final int X_OFFSET = 20; /** * 横线上文字的纵向偏移量 */ private static final int Y_OFFSET = 10; /** * 中心坐标 */ private int centerX; private int centerY; /** * 半径 */ private float radius; /** * 弧形外接矩形 */ private RectF rectF; /** * 中间文本的大小 */ private Rect centerTextBound = new Rect(); /** * 数据文本的大小 */ private Rect dataTextBound = new Rect(); /** * 扇形画笔 */ private Paint mArcPaint; /** * 中心文本画笔 */ private Paint centerTextPaint; /** * 数据画笔 */ private Paint dataPaint; /** * 数据源数字数组 */ private int[] numbers; /** * 数据源名称数组 */ private String[] names; /** * 数据源总和 */ private int sum; /** * 颜色数组 */ private int[] colors; private Random random = new Random(); //自定义属性 Start /** * 中间字体大小 */ private float centerTextSize = 50; /** * 数据字体大小 */ private float dataTextSize = 20; /** * 中间字体颜色 */ private int centerTextColor = Color.BLACK; /** * 数据字体颜色 */ private int dataTextColor = Color.BLACK; /** * 圆圈的宽度 */ private float circleWidth = 50; //自定义属性 End public LinePieView(Context context) { super(context); init(); } public LinePieView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public LinePieView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray typedArray = context.obtainStyledAttributes(attrs, com.don.pieviewlibrary.R.styleable.PieView); centerTextSize = typedArray.getDimension(com.don.pieviewlibrary.R.styleable.PieView_centerTextSize, centerTextSize); dataTextSize = typedArray.getDimension(com.don.pieviewlibrary.R.styleable.PieView_dataTextSize, dataTextSize); circleWidth = typedArray.getDimension(com.don.pieviewlibrary.R.styleable.PieView_circleWidth, circleWidth); centerTextColor = typedArray.getColor(com.don.pieviewlibrary.R.styleable.PieView_centerTextColor, centerTextColor); dataTextColor = typedArray.getColor(com.don.pieviewlibrary.R.styleable.PieView_dataTextColor, dataTextColor); typedArray.recycle(); init(); } /** * 初始化 */ private void init() { mArcPaint = new Paint(); mArcPaint.setStrokeWidth(circleWidth); mArcPaint.setAntiAlias(true); mArcPaint.setStyle(Paint.Style.STROKE); centerTextPaint = new Paint(); centerTextPaint.setTextSize(centerTextSize); centerTextPaint.setAntiAlias(true); centerTextPaint.setColor(centerTextColor); dataPaint = new Paint(); dataPaint.setStrokeWidth(2); dataPaint.setTextSize(dataTextSize); dataPaint.setAntiAlias(true); dataPaint.setColor(dataTextColor); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int measureWidthSize = MeasureSpec.getSize(widthMeasureSpec); int measureHeightSize = MeasureSpec.getSize(heightMeasureSpec); int measureWidthMode = MeasureSpec.getMode(widthMeasureSpec); int measureHeightMode = MeasureSpec.getMode(heightMeasureSpec); if (measureWidthMode == MeasureSpec.AT_MOST && measureHeightMode == MeasureSpec.AT_MOST) { setMeasuredDimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } else if (measureWidthMode == MeasureSpec.AT_MOST) { setMeasuredDimension(DEFAULT_WIDTH, measureHeightSize); } else if (measureHeightMode == MeasureSpec.AT_MOST) { setMeasuredDimension(measureWidthSize, DEFAULT_HEIGHT); } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); centerX = getMeasuredWidth() / 2; centerY = getMeasuredHeight() / 2; //设置半径为宽高最小值的1/4 radius = Math.min(getMeasuredWidth(), getMeasuredHeight()) / 4; //设置扇形外接矩形 rectF = new RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); calculateAndDraw(canvas); } /** * 计算比例并且绘制扇形和数据 */ private void calculateAndDraw(Canvas canvas) { if (numbers == null || numbers.length == 0) { return; } //扇形开始度数 int startAngle = 0; //所占百分比 float percent; //所占度数 float angle; for (int i = 0; i < numbers.length; i++) { percent = numbers[i] / (float) sum; //获取百分比在360中所占度数 if (i == numbers.length - 1) {//保证所有度数加起来等于360 angle = 360 - startAngle; } else { angle = (float) Math.ceil(percent * 360); } //绘制第i段扇形 drawArc(canvas, startAngle, angle, colors[i]); startAngle += angle; //绘制数据 if (numbers[i] <= 0) { continue; } //当前扇形弧线相对于纵轴的中心点度数,由于扇形的绘制是从三点钟方向开始,所以加90 float arcCenterDegree = 90 + startAngle - angle / 2; drawData(canvas, arcCenterDegree, i, percent); } //绘制中心数字总和 canvas.drawText(sum + "", centerX - centerTextBound.width() / 2, centerY + centerTextBound.height() / 2, centerTextPaint); } /** * 计算每段弧度的中心坐标 * * @param degree 当前扇形中心度数 */ private float[] calculatePosition(float degree) { //由于Math.sin(double a)中参数a不是度数而是弧度,所以需要将度数转化为弧度 //而Math.toRadians(degree)的作用就是将度数转化为弧度 //sin 一二正,三四负 sin(180-a)=sin(a) //扇形弧线中心点距离圆心的x坐标 float x = (float) (Math.sin(Math.toRadians(degree)) * radius); //cos 一四正,二三负 //扇形弧线中心点距离圆心的y坐标 float y = (float) (Math.cos(Math.toRadians(degree)) * radius); //每段弧度的中心坐标(扇形弧线中心点相对于view的坐标) float startX = centerX + x; float startY = centerY - y; float[] position = new float[2]; position[0] = startX; position[1] = startY; return position; } /** * 绘制数据 * * @param canvas 画布 * @param degree 第i段弧线中心点相对于纵轴的夹角度数 * @param i 第i段弧线 * @param percent 数据百分比 */ private void drawData(Canvas canvas, float degree, int i, float percent) { //弧度中心坐标 float startX = calculatePosition(degree)[0]; float startY = calculatePosition(degree)[1]; //斜线结束坐标 float endX = 0; float endY = 0; //横线结束坐标 float horEndX = 0; float horEndY = 0; //数字开始坐标 float numberStartX = 0; float numberStartY = 0; //文本开始坐标 float textStartX = 0; float textStartY = 0; //根据每个弧度的中心点坐标绘制数据 dataPaint.getTextBounds(names[i], 0, names[i].length(), dataTextBound); //根据角度判断象限,并且计算各个坐标点 if (degree > 90 && degree < 180) {//二象限 endX = startX + SlASH_LINE_OFFSET; endY = startY + SlASH_LINE_OFFSET; horEndX = endX + HOR_LINE_LENGTH; horEndY = endY; numberStartX = endX + X_OFFSET; numberStartY = endY - Y_OFFSET; textStartX = endX + X_OFFSET; textStartY = endY + dataTextBound.height() + Y_OFFSET / 2; } else if (degree == 180) { startX = centerX; startY = centerY + radius; endX = startX + SlASH_LINE_OFFSET; endY = startY + SlASH_LINE_OFFSET; horEndX = endX + HOR_LINE_LENGTH; horEndY = endY; numberStartX = endX + X_OFFSET; numberStartY = endY - Y_OFFSET; textStartX = endX + X_OFFSET; textStartY = endY + dataTextBound.height() + Y_OFFSET / 2; } else if (degree > 180 && degree < 270) {//三象限 endX = startX - SlASH_LINE_OFFSET; endY = startY + SlASH_LINE_OFFSET; horEndX = endX - HOR_LINE_LENGTH; horEndY = endY; numberStartX = endX - HOR_LINE_LENGTH + X_OFFSET; numberStartY = endY - Y_OFFSET; textStartX = endX - HOR_LINE_LENGTH + X_OFFSET; textStartY = endY + dataTextBound.height() + Y_OFFSET / 2; } else if (degree == 270) { startX = centerX - radius; startY = centerY; endX = startX - SlASH_LINE_OFFSET; endY = startY - SlASH_LINE_OFFSET; horEndX = endX - HOR_LINE_LENGTH; horEndY = endY; numberStartX = endX - HOR_LINE_LENGTH + X_OFFSET; numberStartY = endY - Y_OFFSET; textStartX = endX - HOR_LINE_LENGTH + X_OFFSET; textStartY = endY + dataTextBound.height() + Y_OFFSET / 2; } else if (degree > 270 && degree < 360) {//四象限 endX = startX - SlASH_LINE_OFFSET; endY = startY - SlASH_LINE_OFFSET; horEndX = endX - HOR_LINE_LENGTH; horEndY = endY; numberStartX = endX - HOR_LINE_LENGTH + X_OFFSET; numberStartY = endY - Y_OFFSET; textStartX = endX - HOR_LINE_LENGTH + X_OFFSET; textStartY = endY + dataTextBound.height() + Y_OFFSET / 2; } else if (degree == 360) { startX = centerX; startY = centerY - radius; endX = startX - SlASH_LINE_OFFSET; endY = startY - SlASH_LINE_OFFSET; horEndX = endX - HOR_LINE_LENGTH; horEndY = endY; numberStartX = endX - HOR_LINE_LENGTH + X_OFFSET; numberStartY = endY - Y_OFFSET; textStartX = endX - HOR_LINE_LENGTH + X_OFFSET; textStartY = endY + dataTextBound.height() + Y_OFFSET / 2; } else if (degree > 360) {//一象限 endX = startX + SlASH_LINE_OFFSET; endY = startY - SlASH_LINE_OFFSET; horEndX = endX + HOR_LINE_LENGTH; horEndY = endY; numberStartX = endX + X_OFFSET; numberStartY = endY - Y_OFFSET; textStartX = endX + X_OFFSET; textStartY = endY + dataTextBound.height() + Y_OFFSET / 2; } //绘制折线 canvas.drawLine(startX, startY, endX, endY, dataPaint); //绘制横线 canvas.drawLine(endX, endY, horEndX, horEndY, dataPaint); //绘制数字 canvas.drawText(numbers[i] + "", numberStartX, numberStartY, dataPaint); //绘制文字 canvas.drawText(names[i] + "", textStartX, textStartY, dataPaint); } /** * 绘制扇形 * * @param canvas 画布 * @param startAngle 开始度数 * @param angle 扇形的度数 * @param color 颜色 */ private void drawArc(Canvas canvas, float startAngle, float angle, int color) { mArcPaint.setColor(color); //+0.5是为了让每个扇形之间没有间隙 if (angle != 0) { angle += 0.5f; } canvas.drawArc(rectF, startAngle, angle, false, mArcPaint); } /** * 生成随机颜色 */ private int randomColor() { int red = random.nextInt(256); int green = random.nextInt(256); int blue = random.nextInt(256); return Color.rgb(red, green, blue); } /** * 设置数据(使用随机颜色) * * @param numbers 数字数组 * @param names 名称数组 */ public void setData(int[] numbers, String[] names) { if (numbers == null || numbers.length == 0 || names == null || names.length == 0) { return; } if (numbers.length != names.length) { return; } this.numbers = numbers; this.names = names; colors = new int[numbers.length]; sum = 0; for (int i = 0; i < this.numbers.length; i++) { //计算总和 sum += numbers[i]; //随机颜色 colors[i] = randomColor(); } //计算总和数字的宽高 centerTextPaint.getTextBounds(sum + "", 0, (sum + "").length(), centerTextBound); invalidate(); } /** * 设置数据(自定义颜色) * * @param numbers 数字数组 * @param names 名称数组 * @param colors 颜色数组 */ public void setData(int[] numbers, String[] names, int[] colors) { if (numbers == null || numbers.length == 0 || names == null || names.length == 0 || colors == null || colors.length == 0) { return; } if (numbers.length != names.length || numbers.length != colors.length) { return; } this.numbers = numbers; this.names = names; this.colors = colors; sum = 0; for (int i = 0; i < this.numbers.length; i++) { //计算总和 sum += numbers[i]; } //计算总和数字的宽高 centerTextPaint.getTextBounds(sum + "", 0, (sum + "").length(), centerTextBound); invalidate(); } }

 

 

 

 

 

 

效果图:

 

Android 饼状图,和 柱状图 ,自定义控件_第2张图片

 

柱状图代码:

柱状图XML:




    

        

        

        

        

        

        

        


    

 

红色代表核心

import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.DecelerateInterpolator;
import android.widget.Scroller;

import com.dunqi.gpm.chaotian.R;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
* _oo0oo_
* o8888888o
* 88" . "88
* (| -_- |)
* 0\  =  /0
* ___/`---'\___
* .' \\|     |// '.
* / \\|||  :  |||// \
* / _||||| -卍-|||||- \
* |   | \\\  -  /// |   |
* | \_|  ''\---/''  |_/ |
* \  .-\__  '-'  ___/-. /
* ___'. .'  /--.--\  `. .'___
* ."" '<  `.___\_<|>_/___.' >' "".
* | | :  `- \`.;`\ _ /`;.`/ - ` : | |
* \  \ `_.   \_ __\ /__ _/   .-` /  /
* =====`-.____`.___ \_____/___.-`___.-'=====
* `=---='
* 佛祖保佑        永无BUG
* 佛曰:
* 程序园里程序天,程序天里程序员;
* 程序猿人写程序,又拿程序换肉钱。
* 肉饱继续桌前坐,饱暖还是桌前眠;
* 半迷半醒日复日,码上码下年复年。
* 但愿叱咤互联世,不愿搬砖码当前;
* 诸葛周瑜算世事,我来算出得加钱。
* 别人笑我忒直男,我笑自己太像猿;
* 但见重庆府国内,处处地地程序员。
* Created by HCJ
* ${DATA}
* 柱状图
*/
public class BarChartNew extends View {
    private Context mContext;
    /**
     * 视图的宽和高  刻度区域的最大值
     */
    private int mTotalWidth, mTotalHeight, maxHeight;
    private int paddingRight, paddingBottom, paddingTop;
    //柱形图的颜色集合
    private int barColors[];
    //距离底部的多少 用来显示底部的文字
    private int bottomMargin;
    //距离顶部的多少 用来显示顶部的文字
    private int topMargin;
    private int rightMargin;
    private int leftMargin;
    /**
     * 画笔 轴 刻度 柱子 点击后的柱子 单位
     */
    private Paint axisPaint, textPaint, barPaint, borderPaint, unitPaint;
    private List mData;//数据集合
    /**
     * item中的Y轴最大值
     */
    private float maxYValue;
    /**
     * Y轴最大的刻度值
     */
    private float maxYDivisionValue;
    /**
     * 柱子的矩形
     */
    private Rect mBarRect, mBarRectClick;
    /**
     * 绘制的区域
     */
    private RectF mDrawArea;
    /**
     * 每一个bar的宽度
     */
    private int barWidth;
    /**
     * 每个bar之间的距离
     */
    private int barSpace;
    /**
     * 向右边滑动的距离
     */
    private float leftMoving;
    /**
     * 左后一次的x坐标
     */
    private float lastPointX;
    /**
     * 当前移动的距离
     */
    private float movingThisTime = 0.0f;
    /**
     * 右边的最大和最小值
     */
    private int maxRight, minRight;
    /**
     * 下面两个相当于图表的原点
     */
    private float mStartX;
    private int mStartY;
    /**
     * 柱形图左边的x轴坐标 和右边的x轴坐标
     */
    private List mBarLeftXPoints = new ArrayList<>();
    private List mBarRightXPoints = new ArrayList<>();

    /* 用户点击到了无效位置 */
    public static final int INVALID_POSITION = -1;
    private OnItemBarClickListener mOnItemBarClickListener;
    private GestureDetector mGestureListener;
    /**
     * 是否绘制点击效果
     */
    private boolean isDrawBorder;
    /**
     * 点击的地方
     */
    private int mClickPosition;

    //滑动速度相关
    private VelocityTracker velocityTracker;
    private Scroller scroller;
    /**
     * fling最大速度
     */
    private int maxVelocity;
    //x轴 y轴的单位
    private String unitX;
    private String unitY;

    public void setOnItemBarClickListener(OnItemBarClickListener onRangeBarClickListener) {
        this.mOnItemBarClickListener = onRangeBarClickListener;
    }

    public interface OnItemBarClickListener {
        void onClick(int position);
    }

    public BarChartNew(Context context) {
        super(context);
        init(context);
    }

    public BarChartNew(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public BarChartNew(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        mContext = context;
        barWidth = DensityUtil.dip2px(getContext(), 40);
        barSpace = DensityUtil.dip2px(getContext(), 40);
        topMargin = DensityUtil.dip2px(getContext(), 20);
        bottomMargin = DensityUtil.dip2px(getContext(), 30);
        rightMargin = DensityUtil.dip2px(getContext(), 40);
        leftMargin = DensityUtil.dip2px(getContext(), 10);

        scroller = new Scroller(context);
        maxVelocity = ViewConfiguration.get(context).getScaledMaximumFlingVelocity();
        mGestureListener = new GestureDetector(context, new RangeBarOnGestureListener());

        axisPaint = new Paint();
        axisPaint.setColor(ContextCompat.getColor(mContext, R.color.color_1f74c9));
        axisPaint.setStrokeWidth(1);

        textPaint = new Paint();
        textPaint.setAntiAlias(true);
        textPaint.setTextSize(DensityUtil.dip2px(getContext(), 10));

        unitPaint = new Paint();
        unitPaint.setAntiAlias(true);
        Typeface typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD);
        unitPaint.setTypeface(typeface);
        unitPaint.setTextSize(DensityUtil.dip2px(getContext(), 10));

        barPaint = new Paint();
        barPaint.setColor(barColors != null && barColors.length > 0 ? barColors[0] : Color.parseColor("#6FC5F4"));

        borderPaint = new Paint();
        borderPaint.setAntiAlias(true);
        borderPaint.setStyle(Paint.Style.FILL);
        borderPaint.setColor(Color.rgb(0, 0, 0));
        borderPaint.setAlpha(120);

        mBarRect = new Rect(0, 0, 0, 0);
        mBarRectClick = new Rect(0, 0, 0, 0);
        mDrawArea = new RectF(0, 0, 0, 0);
    }

    public void setData(List list, int colors[], String unitX, String unitY) {
        this.mData = list;
        this.barColors = colors;
        this.unitX = unitX;
        this.unitY = unitY;
        if (list != null && list.size() > 0) {
            maxYValue = calculateMax(list);
            getRange(maxYValue);
        }
    }

    /**
     * 计算出Y轴最大值
     *
     * @return
     */
    private float calculateMax(List list) {
        float start = list.get(0).getSum();
        for (BarChartEntity entity : list) {
            if (entity.getSum() > start) {
                start = entity.getSum();
            }
        }
        return start;
    }

    /**
     * 得到柱状图的最大和最小的分度值
     */
    private void getRange(float maxYValue) {
//        maxYValue = 12.50f;
        int scale = CalculateUtil.getScale(maxYValue);//获取这个最大数 数总共有几位
        float unScaleValue = (float) (maxYValue / Math.pow(10, scale));//最大值除以位数之后剩下的值  比如1200/1000 后剩下1.2
        maxYDivisionValue = (float) (CalculateUtil.getRangeTop(unScaleValue) * Math.pow(10, scale));//获取Y轴的最大的分度值
        mStartX = CalculateUtil.getDivisionTextMaxWidth(maxYDivisionValue, mContext) + 20;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mTotalWidth = w;
        mTotalHeight = h;
        maxHeight = h - getPaddingTop() - getPaddingBottom() - bottomMargin - topMargin;
        paddingBottom = getPaddingBottom();
        paddingTop = getPaddingTop();
        int paddingLeft = getPaddingLeft();
        paddingRight = getPaddingRight();

    }

    //获取滑动范围和指定区域
    private void getArea() {
        maxRight = (int) (mStartX + (barSpace + barWidth) * mData.size());
        minRight = mTotalWidth - leftMargin - rightMargin;
        mStartY = mTotalHeight - bottomMargin - paddingBottom;
        mDrawArea = new RectF(mStartX, paddingTop, mTotalWidth - paddingRight - rightMargin, mTotalHeight - paddingBottom);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mData == null || mData.isEmpty()) return;
        getArea();
        checkTheLeftMoving();
        //绘制刻度线 和 刻度
        drawScaleLine(canvas);
        //绘制单位
        drawUnit(canvas);
        //调用clipRect()方法后,只会显示被裁剪的区域
        canvas.clipRect(mDrawArea.left, mDrawArea.top, mDrawArea.right, mDrawArea.bottom + mDrawArea.height());
        //绘制柱子
        drawBar(canvas);
        //绘制X轴的text
        drawXAxisText(canvas);
    }

    private void drawUnit(Canvas canvas) {
        String textLength = maxYDivisionValue % 5 == 0 ? String.valueOf((int) maxYDivisionValue) : String.valueOf(maxYDivisionValue);
        canvas.drawText(unitY, mStartX - textPaint.measureText(textLength), topMargin / 2, unitPaint);
        canvas.drawText(unitX, mTotalWidth - rightMargin - paddingRight + 10, mTotalHeight - bottomMargin / 2, unitPaint);
    }

    /**
     * 检查向左滑动的距离 确保没有画出屏幕
     */
    private void checkTheLeftMoving() {
        if (leftMoving > (maxRight - minRight)) {
            leftMoving = maxRight - minRight;
        }
        if (leftMoving < 0) {
            leftMoving = 0;
        }
    }

    private void drawXAxisText(Canvas canvas) {
        //这里设置 x 轴的字一条最多显示5个,大于三个就换行
        for (int i = 0; i < mData.size(); i++) {
            String text = mData.get(i).getxLabel();
            if (text.length() <= 5) {
                canvas.drawText(text, mBarLeftXPoints.get(i) - (textPaint.measureText(text) - barWidth) / 2, mTotalHeight - bottomMargin * 2 / 3, textPaint);
            } else {
                String text1 = text.substring(0, 3);
                String text2 = text.substring(3, text.length());
                canvas.drawText(text1, mBarLeftXPoints.get(i) - (textPaint.measureText(text1) - barWidth) / 2, mTotalHeight - bottomMargin * 2 / 3, textPaint);
                canvas.drawText(text2, mBarLeftXPoints.get(i) - (textPaint.measureText(text2) - barWidth) / 2, mTotalHeight - bottomMargin / 3, textPaint);
            }
        }
    }

    private float percent = 1f;
    private TimeInterpolator pointInterpolator = new DecelerateInterpolator();

    public void startAnimation() {
        ValueAnimator mAnimator = ValueAnimator.ofFloat(0, 1);
        mAnimator.setDuration(2000);
        mAnimator.setInterpolator(pointInterpolator);
        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                percent = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        mAnimator.start();
    }

    private void drawBar(Canvas canvas) {
        mBarLeftXPoints.clear();
        mBarRightXPoints.clear();
        mBarRect.bottom = mStartY;
        for (int i = 0; i < mData.size(); i++) {
            if (barColors.length == 1) {
                mBarRect.left = (int) (mStartX + barWidth * i + barSpace * (i + 1) - leftMoving);
                mBarRect.top = mStartY - (int) ((maxHeight * (mData.get(i).getyValue() / maxYDivisionValue)) * percent);
                mBarRect.right = mBarRect.left + barWidth;
                canvas.drawRect(mBarRect, barPaint);
            } else {
                int eachHeight = 0;//每一块的高度
                mBarRect.left = (int) (mStartX + barWidth * i + barSpace * (i + 1) - leftMoving);
                mBarRect.right = mBarRect.left + barWidth;
                for (int j = 0; j < barColors.length; j++) {
                    barPaint.setColor(barColors[j]);
                    mBarRect.bottom = (int) (mStartY - eachHeight * percent);
                    eachHeight += (int) ((maxHeight * (mData.get(i).getyValue() / maxYDivisionValue)));
                    mBarRect.top = (int) (mBarRect.bottom - ((maxHeight * (mData.get(i).getyValue() / maxYDivisionValue))) * percent);
                    canvas.drawRect(mBarRect, barPaint);
                }
            }
            mBarLeftXPoints.add(mBarRect.left);
            mBarRightXPoints.add(mBarRect.right);
        }
        if (isDrawBorder) {
            drawBorder(mClickPosition);
            canvas.drawRect(mBarRectClick, borderPaint);
        }
    }

    private void drawBorder(int position) {
        mBarRectClick.left = (int) (mStartX + barWidth * position + barSpace * (position + 1) - leftMoving);
        mBarRectClick.right = mBarRectClick.left + barWidth;
        mBarRectClick.bottom = mStartY;
        mBarRectClick.top = mStartY - (int) (maxHeight * (mData.get(position).getSum() / maxYDivisionValue));
    }

    /**
     * Y轴上的text (1)当最大值大于1 的时候 将其分成5份 计算每个部分的高度  分成几份可以自己定
     * (2)当最大值大于0小于1的时候  也是将最大值分成5份
     * (3)当为0的时候使用默认的值
     */
    private void drawScaleLine(Canvas canvas) {
        float eachHeight = (maxHeight / 5f);
        float textValue = 0;
        if (maxYValue > 1) {
            for (int i = 0; i <= 5; i++) {
                float startY = mStartY - eachHeight * i;
                BigDecimal maxValue = new BigDecimal(maxYDivisionValue);
                BigDecimal fen = new BigDecimal(0.2 * i);
                String text = null;
                //因为图表分了5条线,如果能除不进,需要显示小数点不然数据不准确
                if (maxYDivisionValue % 5 != 0) {
                    text = String.valueOf(maxValue.multiply(fen).floatValue());
                } else {
                    text = String.valueOf(maxValue.multiply(fen).longValue());
                }
                canvas.drawText(text, mStartX - textPaint.measureText(text) - 5, startY + textPaint.measureText("0") / 2, textPaint);
                canvas.drawLine(mStartX, startY, mTotalWidth - paddingRight - rightMargin, startY, axisPaint);
            }
        } else if (maxYValue > 0 && maxYValue <= 1) {
            for (int i = 0; i <= 5; i++) {
                float startY = mStartY - eachHeight * i;
                textValue = CalculateUtil.numMathMul(maxYDivisionValue, (float) (0.2 * i));
                String text = String.valueOf(textValue);
                canvas.drawText(text, mStartX - textPaint.measureText(text) - 5, startY + textPaint.measureText("0") / 2, textPaint);
                canvas.drawLine(mStartX, startY, mTotalWidth - paddingRight - rightMargin, startY, axisPaint);
            }
        } else {
            for (int i = 0; i <= 5; i++) {
                float startY = mStartY - eachHeight * i;
                String text = String.valueOf(10 * i);
                canvas.drawText(text, mStartX - textPaint.measureText(text) - 5, startY + textPaint.measureText("0") / 2, textPaint);
                canvas.drawLine(mStartX, startY, mTotalWidth - paddingRight - rightMargin, startY, axisPaint);
            }
        }
    }

    private void initOrResetVelocityTracker() {
        if (velocityTracker == null) {
            velocityTracker = VelocityTracker.obtain();
        } else {
            velocityTracker.clear();
        }
    }

    private void recycleVelocityTracker() {
        if (velocityTracker != null) {
            velocityTracker.recycle();
            velocityTracker = null;
        }
    }

    @Override
    public void computeScroll() {
        if (scroller.computeScrollOffset()) {
            movingThisTime = (scroller.getCurrX() - lastPointX);
            leftMoving = leftMoving + movingThisTime;
            lastPointX = scroller.getCurrX();
            postInvalidate();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastPointX = event.getX();
                scroller.abortAnimation();//终止动画
                initOrResetVelocityTracker();
                velocityTracker.addMovement(event);//将用户的移动添加到跟踪器中。
                break;
            case MotionEvent.ACTION_MOVE:
                float movex = event.getX();
                movingThisTime = lastPointX - movex;
                leftMoving = leftMoving + movingThisTime;
                lastPointX = movex;
                invalidate();
                velocityTracker.addMovement(event);
                break;
            case MotionEvent.ACTION_UP:
                velocityTracker.addMovement(event);
                velocityTracker.computeCurrentVelocity(1000, maxVelocity);
                int initialVelocity = (int) velocityTracker.getXVelocity();
                velocityTracker.clear();
                scroller.fling((int) event.getX(), (int) event.getY(), -initialVelocity / 2,
                        0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0);
                invalidate();
                lastPointX = event.getX();
                break;
            case MotionEvent.ACTION_CANCEL:
                recycleVelocityTracker();
                break;
            default:
                return super.onTouchEvent(event);
        }
        if (mGestureListener != null) {
            mGestureListener.onTouchEvent(event);
        }
        return true;
    }

    /**
     * 点击
     */
    private class RangeBarOnGestureListener implements GestureDetector.OnGestureListener {
        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        @Override
        public void onShowPress(MotionEvent e) {
        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            int position = identifyWhichItemClick(e.getX(), e.getY());
            if (position != INVALID_POSITION && mOnItemBarClickListener != null) {
                mOnItemBarClickListener.onClick(position);
                setClicked(position);
                invalidate();
            }
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            return false;
        }

        @Override
        public void onLongPress(MotionEvent e) {
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            return false;
        }
    }

    /**
     * 设置选中的位置
     *
     * @param position
     */
    public void setClicked(int position) {
        isDrawBorder = true;
        mClickPosition = position;
    }

    /**
     * 根据点击的手势位置识别是第几个柱图被点击
     *
     * @param x
     * @param y
     * @return -1时表示点击的是无效位置
     */
    private int identifyWhichItemClick(float x, float y) {
        float leftx = 0;
        float rightx = 0;
        if (mData != null) {
            for (int i = 0; i < mData.size(); i++) {
                leftx = mBarLeftXPoints.get(i);
                rightx = mBarRightXPoints.get(i);
                if (x < leftx) {
                    break;
                }
                if (leftx <= x && x <= rightx) {
                    return i;
                }
            }
        }
        return INVALID_POSITION;
    }
}
 //饼状图
    implementation 'com.zhijieeeeee:pieviewlibrary:2.0.0'
    implementation 'com.github.PhilJay:MPAndroidChart:v3.0.0'

 

你可能感兴趣的:(one)