Android 柱状图

package com.wei.demo.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.support.annotation.Dimension;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewConfiguration;
import android.webkit.WebSettings;
import android.widget.TextView;
import android.widget.Toast;

import com.wei.demo.ColumnBean;
import com.wei.demo.ColumnLocation;

import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.util.ArrayList;

/**
* Created by ${wei} on 2016/12/15.
*/

public class ChartView extends SurfaceView {
private static final String TAG = “zpy_ChartView”;

private ArrayList<ColumnBean> list = new ArrayList<>();
private Context context;

//默认线的颜色
private static final String LINECOLOR = "#666666";
//负值的颜色
private static final String BLUECOLOR = "#8800ffff";
//正值的颜色
private static final String REDCOLOR = "#666666";
//边距
private final int MARGIN = 24;
private final int MARGINTOP = 48;
private final int MARGINBOTTOM = 48;
private final int VERTICALSPEC = 10;//柱状图间距
private int mHeight;
private int mWidth;
private int avarageLine;
private float mColumnWidth;
private double avarageValue;//平均值
private GestureDetector gestureDetector;
private int touchSlop;
private int downX;
private static boolean isLongPress;
private final int STOREWIDTH = 3;
//底部背景日期颜色
private final String COLOR_BOTTOMDATEBG = "#88E2EBF9";
//底部日期颜色
private final String COLOR_BOTTOMDATE = "#66666666";
//虚线的颜色
private final String COLOR_DASHLINE = "#999999";
//边框的颜色
private final String COLOR_BOX = "#999999";
private int index;
private boolean isCanvas;
private int dateIndex;
private boolean isSet;
private int orange;
private boolean isMoveLeft, isMoveRight;
private int textsize = 14;

private ArrayList<ColumnLocation> locations = new ArrayList<>();

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

public ChartView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

public ChartView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mWidth = w - MARGIN * 2;
    mHeight = h - MARGINTOP - MARGINBOTTOM * 2;
    //每个柱状图的宽度 整体宽度-左右边距 - 左右线的宽度 - 间隔
    mColumnWidth = (mWidth - STOREWIDTH * 2 - VERTICALSPEC * 30) / 31.0f;
}

private void init(Context context) {
    this.context = context;
    //系统认为最小的滑动距离
    isSet = false;
    touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    gestureDetector = new GestureDetector(context, new MyGustrueListener());

    textsize = dp2px(textsize);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    setMeasuredDimension(widthSize, heightSize);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //绘制边框及虚线
    drawBox(canvas);
    if (isSet) {
        //绘制左侧数值
        drawLeftText(canvas);
        //绘制柱状图
        //平均值不等于0 的时候开始绘制
        drawColumnBitmap(canvas);
    }
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    int action = event.getAction();
    switch (action) {
        case MotionEvent.ACTION_DOWN:
            downX = (int) event.getX();
            break;
        case MotionEvent.ACTION_MOVE:
            int moveX = (int) event.getX();
            int moveY = (int) event.getY();
            int diffX = Math.abs(moveX - downX);
            int finalMoveX = moveX - MARGIN;//减去左侧边距
            //滑动只在范围内开始绘制虚线
            if (isLongPress && moveX > MARGIN && moveX < (mWidth + MARGIN) && moveY > MARGINTOP && moveY < (MARGINTOP + mHeight)) {
                if (diffX >= touchSlop) {
                    isCanvas = true;
                    calculateLong(finalMoveX);
                } else {
                    isCanvas = false;
                }
            } else {
                isCanvas = false;

                if (list.size() > 31) {
                    if (moveX - downX > 0 && !isMoveLeft) {
                        orange = moveX - downX + orange;
                        downX = (int) event.getX();
                        postInvalidate();
                    } else if (moveX - downX < 0 && !isMoveRight) {
                        orange = moveX - downX + orange;
                        downX = (int) event.getX();
                        postInvalidate();
                    }
                }
            }
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            isLongPress = false;
            postInvalidate();
            break;
    }
    return gestureDetector.onTouchEvent(event);
}

/**
 * 绘制框架
 */

private void drawBox(Canvas canvas) {
    Paint paint = getLinePaint();
    //绘制边框
    Path path = new Path();
    path.moveTo(MARGIN, MARGINTOP);
    path.lineTo(mWidth + MARGIN, MARGINTOP);
    path.lineTo(mWidth + MARGIN, mHeight + MARGINTOP);
    path.lineTo(MARGIN, mHeight + MARGINTOP);
    path.lineTo(MARGIN, MARGINTOP);
    path.close();
    canvas.drawPath(path, paint);
    path.reset();

    //平均值
    avarageLine = mHeight / 6;
    //绘制横线
    paint.setPathEffect(new DashPathEffect(new float[]{8, 8}, 0));
    paint.setColor(Color.parseColor(COLOR_DASHLINE));
    for (int i = 1; i <= 5; i++) {
        int startY = MARGINTOP + avarageLine * i;
        canvas.drawLine(MARGIN, startY, mWidth + MARGIN, startY, paint);
    }
}


/**
 * 绘制左侧数值
 **/
private void drawLeftText(Canvas canvas) {
    Paint paint = getTextPaint(COLOR_BOTTOMDATE, 30);
    int maxValueIndex = getMaxValueIndex();
    if (maxValueIndex == -1) {
        return;
    }
    double[] doubles = calculateAvarage(list.get(maxValueIndex).getValue());
    if (doubles == null || doubles.length == 0) {
        return;
    }
    String[] leftValues = new String[doubles.length];
    //转换成字符串
    for (int i = 0; i < doubles.length; i++) {
        double aDouble = doubles[i];

        if (aDouble > 0) {
            leftValues[i] = String.valueOf(String.format("%s%s", "+", formatValue(aDouble)));
        } else if (aDouble == 0) {
            leftValues[i] = String.valueOf(String.format("%s", "0.00"));
        } else leftValues[i] = String.valueOf(formatValue(aDouble));
    }

    for (int i = 0; i < leftValues.length; i++) {
        canvas.drawText(leftValues[i], MARGIN + 10, MARGINTOP - 10 + avarageLine * i, paint);
    }
    paint.reset();
}

/**
 * 绘制柱状图
 */
private void drawColumnBitmap(Canvas canvas) {
    if (list == null || list.size() == 0) {
        Toast.makeText(context, "没有数据", Toast.LENGTH_SHORT).show();
        return;
    }
    Paint paint = getLinePaint();
    paint.setStyle(Paint.Style.FILL);
    int centerLine = avarageLine * 3 + MARGINTOP;

    ColumnBean columnBean = list.get(0);
    String date_value = columnBean.getDate();
    dateIndex = Integer.valueOf(date_value.substring(date_value.lastIndexOf("-") + 1)) - 1;

    for (int i = 0; i < list.size(); i++) {

        ColumnBean columnBean2 = list.get(i);
        String date2 = columnBean2.getDate();
        int index2 = Integer.valueOf(date2.substring(date2.lastIndexOf("-") + 1)) - 1;

        //每个柱图的高度
        double value = list.get(i).getValue();
        double percent = value / avarageValue;//比例
        double endY = Math.abs(percent * avarageLine);
        //y点的结束点
        if (value < 0) {
            paint.setColor(Color.GREEN);
            endY = centerLine + endY;
        } else {
            paint.setColor(Color.RED);
            endY = centerLine - endY;
        }
        endY = formatValue(endY);
        int startX = ((int) (index2 * (mColumnWidth + VERTICALSPEC) + MARGIN + STOREWIDTH) /*+ orange*/);
        int endX = (int) (startX + mColumnWidth);
        int left = MARGIN + STOREWIDTH;

// if (i == 0 && startX >= left) {
// isMoveLeft = true;
// isMoveRight = false;
// }
//
// if (i == list.size() - 1 && endX <= MARGIN + STOREWIDTH + mWidth) {
// isMoveRight = true;
// isMoveLeft = false;
// }
//
// if (startX < left && endX > left) {
// startX = left;
// }
// int right = left + mWidth;
// if (endY > right && startX < right) {
// endX = right;
// }
// Log.e(TAG, “drawColumnBitmap: endx = ” + endX + ” startX = ” + startX + ” i = ” + i + ” ismoveleft = ” + isMoveLeft);
// if (startX >= left && endX <= right) {
Rect rect = new Rect();
rect.left = startX;
rect.top = value < 0 ? centerLine : (int) endY;
rect.right = endX;
rect.bottom = value < 0 ? (int) endY : centerLine;
canvas.drawRect(rect, paint);
// }
}
//非常按时绘制底部日期
if (!isLongPress) {
paint.setTextSize(textsize);
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.parseColor(COLOR_BOTTOMDATE));
String startDate = list.get(0).getDate();
String endDate = list.get(list.size() - 1).getDate();
float textWidth = paint.measureText(startDate);
int startX = (int) ((dateIndex * (mColumnWidth + VERTICALSPEC) + MARGIN + STOREWIDTH) - textWidth / 2);
int endStartX = (int) ((dateIndex + list.size() - 1) * (mColumnWidth + VERTICALSPEC) + MARGIN + STOREWIDTH - textWidth / 2);

        if (startX < MARGIN + STOREWIDTH) {
            startX = MARGIN + STOREWIDTH;
        }
        if (endStartX + textWidth > MARGIN + STOREWIDTH + mWidth) {
            endStartX = (int) (MARGIN + mWidth - textWidth);
        }
        canvas.drawText(startDate, startX, MARGINTOP + mHeight +textsize, paint);
        canvas.drawText(endDate, endStartX, MARGINTOP + mHeight + textsize, paint);

    }

    //绘制虚线
    if (isLongPress) {
        paint.setPathEffect(new DashPathEffect(new float[]{8, 8}, 0));
        paint.setStrokeWidth(STOREWIDTH);
        paint.setColor(Color.GRAY);
        int startX = (int) ((index + dateIndex) * (mColumnWidth + VERTICALSPEC) + MARGIN + STOREWIDTH + mColumnWidth / 2);
        canvas.drawLine(startX, MARGINTOP, startX, MARGINTOP + mHeight, paint);
        paint.reset();
        String date = list.get(index).getDate();
        drawBottomText(canvas, paint, startX, date);

        Log.e(TAG, "drawColumnBitmap: date = " + date);
    }
}


/**
 * 绘制底部日期及背景
 *
 * @param text   文本
 * @param startX 线的起始点X轴
 */
private void drawBottomText(Canvas canvas, Paint paint, int startX, String text) {
    paint.setStyle(Paint.Style.FILL);
    paint.setStrokeWidth(STOREWIDTH);
    //绘制底部日期
    paint.setTextSize(40);

    paint.setColor(Color.parseColor(COLOR_BOTTOMDATEBG));
    int textLength = (int) paint.measureText(text);
    int right = startX + textLength / 2 + VERTICALSPEC;
    int left = startX - textLength / 2 - VERTICALSPEC;
    if (left < MARGIN) {
        left = MARGIN;
        right = left + textLength + VERTICALSPEC * 2;
    }
    if (right > MARGIN + mWidth) {
        right = MARGIN + mWidth;
        left = right - textLength - VERTICALSPEC * 2;
    }
    //绘制日期的背景
    Rect rect = new Rect(left, MARGINTOP + mHeight + VERTICALSPEC, right, MARGINTOP + mHeight + 50 + VERTICALSPEC);
    canvas.drawRect(rect, paint);

    //绘制底部日期
    paint.setTextSize(40);
    paint.setTypeface(Typeface.DEFAULT);
    paint.setTextAlign(Paint.Align.LEFT);
    paint.setColor(Color.parseColor(COLOR_BOTTOMDATE));
    canvas.drawText(text, left + VERTICALSPEC, MARGINTOP + mHeight + 40 + VERTICALSPEC, paint);
}


/**
 * 计算长按事件的位置
 *
 * @param finalMoveX 去除左侧边距的位置
 */
private void calculateLong(int finalMoveX) {
    index = (int) ((finalMoveX - VERTICALSPEC / 2) / (mColumnWidth + VERTICALSPEC));
    if (index > dateIndex + list.size() - 1) {
        index = list.size() - 1;
    } else if (index < dateIndex) {
        index = 0;
    } else {
        index = Math.abs(index - dateIndex);
    }
    if (index < 0) {
        index = 0;
    }
    postInvalidate();
}

/**
 * 虚线及边框的画笔
 */
private Paint getLinePaint() {
    Paint paint = new Paint();
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(STOREWIDTH);
    paint.setAntiAlias(true);
    paint.setAlpha(0);
    paint.setColor(Color.parseColor(COLOR_BOX));
    return paint;
}

/**
 * 获取绘制文本的画笔
 *
 * @param textColor 文本颜色
 * @param textSize  文本大小
 * @return
 */
private Paint getTextPaint(String textColor, int textSize) {
    Paint paint = new Paint();
    paint.setStyle(Paint.Style.FILL);
    paint.setStrokeWidth(STOREWIDTH);
    paint.setAntiAlias(true);
    paint.setTextSize(textSize);
    paint.setAlpha(0);
    paint.setTypeface(Typeface.DEFAULT);
    paint.setTextAlign(Paint.Align.LEFT);
    paint.setColor(Color.parseColor(textColor));
    return paint;
}

/**
 * 获取最大值的索引 如果没有数据返回-1
 */
private int getMaxValueIndex() {
    if (list == null || list.size() == 0) {
        Toast.makeText(context, "没有数据", Toast.LENGTH_SHORT).show();
        return -1;
    }
    int size = list.size();
    double indexValue = Math.abs(list.get(0).getValue());
    int index = 0;
    for (int i = 1; i < size; i++) {
        double tempValue = Math.abs(list.get(i).getValue());
        if (tempValue > indexValue) {
            indexValue = tempValue;
            index = i;
        }
    }
    return index;
}

//设置数据
public void setData(ArrayList<ColumnBean> list) {
    this.list = list;
    isSet = true;
    postInvalidate();
}

//计算平均值 并把左侧文案放到数组中
private double[] calculateAvarage(double maxValue) {
    if (maxValue == 0) {
        Toast.makeText(context, "最大值不能是0", Toast.LENGTH_SHORT).show();
        return null;
    }
    avarageValue = maxValue / 3;
    double[] textValue = new double[7];
    int tempIndex = 3;
    //如果最大值是小数则 大-->小 设置数据
    if (maxValue > 0) {
        for (int i = 0; i < 7; i++) {
            textValue[i] = formatValue(avarageValue * (tempIndex--));
            if (tempIndex + 1 == 0) {
                textValue[i] = 0.00f;
            }
        }
    } else {
        for (int i = 6; i >= 0; i--) {
            textValue[i] = formatValue(avarageValue * (tempIndex--));
            if (tempIndex + 1 == 0) {
                textValue[i] = 0.00f;
            }
        }
    }
    return textValue;
}

/**
 * 全部转换为两位小数
 */
private double formatValue(double value) {
    DecimalFormat decimalFormat = new DecimalFormat("#.00");
    return Double.valueOf(decimalFormat.format(value));
}

private int dp2px(int dpValue) {
    float density = context.getResources().getDisplayMetrics().density;
    return (int) (dpValue * density + 0.5f);
}

private int px2dp(int pxValue) {
    float density = context.getResources().getDisplayMetrics().density;
    return (int) (pxValue / density + 0.5f);
}

private class MyGustrueListener extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }

    @Override
    public void onLongPress(MotionEvent e) {
        isLongPress = true;
        calculateLong((int) (e.getX() - MARGIN));
    }
}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值