android自定义View,实现折线图(二)

效果图:

LineChartView类:

public class LineChartView extends View {

    private int width;
    private int height;
    private float maxValue;//传入数据的最大值
    private int dataNum;//数据总数

    private Paint mPaintBg;//报表背景画笔
    private Paint mPaintCoveredBg;//用于画数据覆盖部分
    private Paint mPaintChartLine;//用于画报表的网格
    private Paint mPaintDataLine;//用于画数据连线
    private Paint mPaintTextDate;//用于画日期文本
    private Paint mPaintCircle;//用于画空心圆
    private Paint mPaintFilledCircle;//用于画实心圆
    private Paint mPaintTextValue;//用于画数据访问量值

    private Path path;

    private HashMap<Integer, PageViewData> dataTotal;//用于得存储传入的总数据
    private float mRange[]=new float[3];

    //传三个数值范围
    public void setRange(float[] range) {
        mRange = range;
    }

    //用一个setPaints()方法,设定所有画笔的属性,增加代码灵活性
    public void setPaints(int bgColor, int coveredBgColor, int chartLineColor
            , int dataLineColor, int textDateColor, int filledCircleColor, int circleColor, int textValueColor) {

        mPaintBg.setColor(bgColor);
        mPaintBg.setStyle(Paint.Style.FILL);

        mPaintCoveredBg.setColor(coveredBgColor);
        mPaintCoveredBg.setStyle(Paint.Style.FILL);

        mPaintCircle.setColor(circleColor);
        mPaintCircle.setStyle(Paint.Style.STROKE);
        mPaintCircle.setStrokeWidth(5);
        mPaintCircle.setAntiAlias(true);

        mPaintFilledCircle.setColor(filledCircleColor);
        mPaintFilledCircle.setStyle(Paint.Style.FILL);
        mPaintFilledCircle.setAntiAlias(true);

        mPaintChartLine.setColor(chartLineColor);
        mPaintChartLine.setStyle(Paint.Style.STROKE);
        mPaintChartLine.setAntiAlias(true);

        mPaintDataLine.setColor(dataLineColor);
        mPaintDataLine.setStyle(Paint.Style.STROKE);
        mPaintDataLine.setStrokeWidth(SizeConvert.dip2px(getContext(), 5));
        mPaintDataLine.setAntiAlias(true);

        mPaintTextDate.setColor(textDateColor);
        mPaintTextDate.setTextSize(SizeConvert.dip2px(getContext(), 10));
        mPaintTextDate.setTextAlign(Paint.Align.CENTER);
        mPaintTextDate.setAntiAlias(true);

        mPaintTextValue.setColor(textValueColor);
        mPaintTextValue.setTextSize(SizeConvert.dip2px(getContext(), 12));
        mPaintTextValue.setTextAlign(Paint.Align.CENTER);
        mPaintTextValue.setAntiAlias(true);

        //重绘
        invalidate();
    }


    //用于设定传入的总数据
    public void setDataTotal(HashMap<Integer, PageViewData> dataTotal) {
        this.dataTotal = dataTotal;
        invalidate();
    }

    public LineChartView(Context context) {
        super(context);
    }

    public LineChartView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaintBg = new Paint();
        mPaintCoveredBg = new Paint();
        mPaintCircle = new Paint();
        mPaintChartLine = new Paint();
        mPaintDataLine = new Paint();
        mPaintTextDate = new Paint();
        mPaintTextValue = new Paint();
        mPaintFilledCircle = new Paint();
        path = new Path();

        dataTotal = new HashMap<>();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //当总数据已经传入,即不为空时,根据总数据中数据个数设定view的总宽
        if (dataTotal != null) {
            width = (dataTotal.size() - 1) * xAddedNum + chartMarginHorizontal * 2;
            getMaxValue(dataTotal);
        }
        height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);
    }


/**
 *   * 用于得到总数据中最大数据
     * @param dataTotal 总数据
     */

    private void getMaxValue(HashMap<Integer, PageViewData> dataTotal) {
        maxValue = 0;
        dataNum = 0;
        for (int key : dataTotal.keySet()) {
            if (dataTotal.get(key).getPageViewValue() > maxValue) {
                maxValue = dataTotal.get(key).getPageViewValue();
            }
            dataNum++;
        }
    }

    private int mChartHeight;//折线图的高
    private int mChartWidth;//折线图的
    private int startX = SizeConvert.dip2px(getContext(), 10);//开始绘制的x坐标
    private int startY = SizeConvert.dip2px(getContext(), 5);//开始绘制的y坐标
    private int chartMarginBottom = SizeConvert.dip2px(getContext(), 30);//折线图距离父控件底部距离
    private int chartMarginHorizontal = SizeConvert.dip2px(getContext(), 12);//折线图距离父控件左右的距离
    private int valueAlignLeft = SizeConvert.dip2px(getContext(), 0);//value参数文本距离左边距离
    private int dateAlignLeft = SizeConvert.dip2px(getContext(), 0);//date参数文本距离左边距离
    private int valueAlignBottom = SizeConvert.dip2px(getContext(), 5);//value参数文本距离底部距离
    private int dateAlignBottom = SizeConvert.dip2px(getContext(), 10);//date参数文本距离底部距离
    private int xAddedNum = SizeConvert.dip2px(getContext(), 60);//绘制折线图时每次移动的x轴距离
    private int yAddedNum;//绘制折线图时每次移动的y轴距离
    private boolean isDrawFirst;//是否是第一次绘制
    private float circleFilledRadius = SizeConvert.dip2px(getContext(), 5);//外圆半径
    private float circleRadius = SizeConvert.dip2px(getContext(), 3);//内圆半径

    private float firstX;//第一个点的x轴坐标
    private float firstY;//第一个点的y轴坐标

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        isDrawFirst = true;
        mChartHeight = height - chartMarginBottom;
        yAddedNum = mChartHeight / 4;
        mChartWidth = width - chartMarginHorizontal * 2;

        canvas.drawRect(startX, startY, startX + mChartWidth, startY + mChartHeight, mPaintBg);
        for (int key : dataTotal.keySet()) {
            float value = dataTotal.get(key).getPageViewValue();
            if (isDrawFirst) {
                //当第一次绘制时得到第一个点的横纵坐标
                firstX = startX;
                firstY = startY + (1f - value / ((int) maxValue * 1.5f)) * mChartHeight;
                path.moveTo(firstX, firstY);
                isDrawFirst = false;
            }
            //每循环一次,将path线性相位一次
            path.lineTo(startX, startY + (1f - value / ((int) maxValue * 1.5f)) * mChartHeight);
            startX += xAddedNum;
        }
        //重新给startX赋值
        startX = SizeConvert.dip2px(getContext(), 10);
        //画出折线
        canvas.drawPath(path, mPaintDataLine);
        //画出折线以下部分的颜色
        path.lineTo(startX + mChartWidth, startY + mChartHeight);
        path.lineTo(startX, startY + mChartHeight);
        path.lineTo(firstX, firstY);
        canvas.drawPath(path, mPaintCoveredBg);

        //画出每个点的圆圈,和对应的文本
        for (int key : dataTotal.keySet()) {
            String date = dataTotal.get(key).getDate();
            float value = dataTotal.get(key).getPageViewValue();

            if(value <= mRange[0]){
                mPaintCircle.setColor(Color.parseColor("#FF0000"));
            }else if(value >= mRange[2]) {
                mPaintCircle.setColor(Color.parseColor("#FBAD5F"));
            }else{
                mPaintCircle.setColor(Color.parseColor("#C8E1A8"));
            }
            canvas.drawCircle(startX, startY + (1f - value / ((int) maxValue * 1.5f)) * mChartHeight, circleFilledRadius, mPaintFilledCircle);
            canvas.drawCircle(startX, startY + (1f - value / ((int) maxValue * 1.5f)) * mChartHeight, circleRadius, mPaintCircle);
            canvas.drawText(date + "", startX + dateAlignLeft, height - dateAlignBottom, mPaintTextDate);
            canvas.drawText(value + "", startX + valueAlignLeft, startY + (1f - value / ((int) maxValue * 1.5f)) * mChartHeight - valueAlignBottom, mPaintTextValue);

            startX += xAddedNum;
        }

        //在次使startX回到初始值
        startX = SizeConvert.dip2px(getContext(), 10);

/**
         * 画出网格
         */

        //竖线
        for (int i = 0; i < dataNum; i++) {
            canvas.drawLine(startX + i * xAddedNum, startY, startX + i * xAddedNum, startY + mChartHeight, mPaintChartLine);
        }

        //横线
        for (int i = 0; i < 5; i++) {
            canvas.drawLine(startX, startY + i * yAddedNum, startX + mChartWidth, startY + i * yAddedNum, mPaintChartLine);
        }

        path.reset();

    }
}

xml文件:

<HorizontalScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="none">
        <com.xx.xx.LineChartView
            android:id="@+id/line_chart_view_item"
            android:layout_width="wrap_content"
            android:layout_height="160dp"/>
 </HorizontalScrollView>

MainActivity:

public class MainActivity extends Activity {    
     private LineChartView mLineChartView;
     private HashMap<Integer,PageViewData> mDataPageView;
 @Override    
 protected void onCreate(Bundle savedInstanceState) {    
  super.onCreate(savedInstanceState);    
  setContentView(R.layout.activity_main);
  mLineChartView = (LineChartView) findViewById(R.id.line_chart_view_item);
  initDataPageView();    
 }
 private void initDataPageView() {
        mDataPageView = new HashMap<>();
        mDataPageView.put(1,new PageViewData(1,"5/1",4.0f));
        mDataPageView.put(2,new PageViewData(2,"5/2",8.5f));
        mDataPageView.put(3,new PageViewData(3,"5/3",5.4f));
        mDataPageView.put(4,new PageViewData(4,"5/4",4.6f));
        mDataPageView.put(5,new PageViewData(5,"5/5",6.2f));
        mDataPageView.put(6,new PageViewData(6,"5/6",4.2f));
        mDataPageView.put(7,new PageViewData(7,"5/7",10.4f));
        mDataPageView.put(8,new PageViewData(8,"5/8",4.4f));
        mDataPageView.put(9,new PageViewData(9,"5/9",5.5f));
        mDataPageView.put(10,new PageViewData(10,"5/10",6.0f));
        mDataPageView.put(11,new PageViewData(11,"5/11",5.4f));
        mDataPageView.put(12,new PageViewData(12,"5/12",3.9f));
        mDataPageView.put(13,new PageViewData(13,"5/13",4.2f));
        mDataPageView.put(14,new PageViewData(14,"5/14",8.0f));
        mDataPageView.put(15,new PageViewData(15,"5/15",11.4f));
        mLineChartView.setDataTotal(mDataPageView);
        mLineChartView.setRange(new float[]{4.4f,7f,10f});//范围
        mLineChartView.setPaints(Color.argb(255,225, 250, 250),
                Color.argb(255,234, 234, 250), Color.argb(255,74,208, 204),
                Color.argb(255,105, 210, 249),Color.argb(255,203, 203, 203)
                ,Color.argb(255,255, 255, 255),Color.argb(255,105, 210, 249),Color.argb(255,105, 210, 249));
    }


下载资源传送门入口:

点击打开链接


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值