Android 红圈营销项目 —— 自定义柱形图和自定义折线图

自定义柱形图

  • 效果:
    这里写图片描述

- 代码:

自定义柱形图HistogramView类:

package com.example.myapplication.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.example.myapplication.R;
import com.example.myapplication.model.HistogramItem;

import java.util.ArrayList;
import java.util.List;


/**
 * 柱形图
 */
public class HistogramView extends View {
    private int width;
    private int height;
    private List<HistogramItem> mList;//存放柱状图的数据
    private Paint mPaintWhite;
    private Paint mPaintBackground;
    private Paint mPaintRate;
    private Paint mPaintName;
    private Paint mPaintHistogramRed;
    private Paint mPaintHistogramGray;


    private int topBar = 60;//百分比占的大小
    private int bottomBar = 60;//名字所占大小
    private int histogramWidth = 50;//柱形宽度
    private int histogramSpacing = 80;//柱形的间距





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

    public HistogramView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //对白色背景画笔进行初始化
        mPaintWhite = new Paint();
        mPaintWhite.setColor(Color.WHITE);

        //对背景灰色进行初始化
        mPaintBackground = new Paint();
        mPaintBackground.setStrokeWidth(2);
        mPaintBackground.setAntiAlias(true);
        mPaintBackground.setColor(getResources().getColor(R.color.histogramback));



        //对写百分比的画笔进行初始化
        mPaintRate = new Paint();
        mPaintRate.setStrokeWidth(2);
        mPaintRate.setAntiAlias(true);
        mPaintRate.setColor(Color.BLACK);
        mPaintRate.setAlpha(50);
      //  mPaintRate.setTextAlign(Paint.Align.CENTER);

        //对名字的画笔进行初始化
        mPaintName = new Paint();
        mPaintName.setStrokeWidth(2);
        mPaintName.setAntiAlias(true);
        mPaintName.setColor(Color.BLACK);
       // mPaintRate.setTextAlign(Paint.Align.CENTER);

        //对红色的柱状体画笔进行初始化
        mPaintHistogramRed = new Paint();
        mPaintHistogramRed.setStrokeWidth(histogramWidth);
        mPaintHistogramRed.setAntiAlias(true);
        mPaintHistogramRed.setColor(Color.argb(0xff, 0xf0, 0x80, 0x80));

        //对柱状体的灰色部分画笔进行初始化
        mPaintHistogramGray = new Paint();
        mPaintHistogramGray.setStrokeWidth(histogramWidth);
        mPaintHistogramGray.setAntiAlias(true);
        mPaintHistogramGray.setColor(Color.GRAY);

    }

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if(mList==null){
            width=   getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        }else {
            width = (int) ((mList.size() + 1) * histogramSpacing);
        }
        height=getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);
        //init();



    }


    /**
     * 绘制
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

//        if (mList==null){
//            canvas.drawColor(getResources().getColor(R.color.histogramback));
//
//        }else {//绘图
        canvas.drawRect(0,0,width,topBar,mPaintWhite);
        canvas.drawRect(0, topBar, width, height - bottomBar, mPaintBackground);
            canvas.drawRect(0, height - bottomBar, width, height, mPaintWhite);
            for (int i = 0;i<mList.size();i++){

                HistogramItem item = mList.get(i);
                Log.d("mlist",item.getName()+"的百分率"+item.getRate());
                canvas.drawLine(histogramSpacing * (i + 1), height - bottomBar, histogramSpacing * (i + 1), topBar, mPaintHistogramGray);//画柱状图的柱形灰色背景
                //画红色的比例部分(注意:先乘比例再除以100)
                canvas.drawLine(histogramSpacing*(i+1),height-bottomBar,histogramSpacing*(i+1),(height-bottomBar)-(height-bottomBar-topBar)*item.getRate()/100,mPaintHistogramRed);

                //画百分比(x坐标要剪掉百分比文字的长度的一半)mPaintRate.measureText(percent)
                String percent  = item.getRate()+"%";
                canvas.drawText(percent, histogramSpacing * (i + 1) - mPaintRate.measureText(percent) / 2, topBar / 2, mPaintRate);
                //画名字(需要宣战画布,正值时逆时针旋转)
                canvas.save();
                canvas.rotate(-45, histogramSpacing * (i + 1), height - bottomBar+10);//旋转的中心点自己来调整
                String name = item.getName();
                //由于文字的末端对应着柱状图中心点,所以文字开始写的位置要从中心点剪掉文字的长度
                canvas.drawText(name,histogramSpacing*(i+1)-mPaintName.measureText(name),height-bottomBar+5,mPaintName);
                canvas.restore();


            }






//        }
    }

//    //更新数据
//    public void init(){//可以在主活动中进行数据的初始化,然后利用上面的setlist方法传到本view中
//        mList = new ArrayList<>();
//        mList.add(new HistogramItem("张三",46));
//        mList.add(new HistogramItem("lisi",35));
//        mList.add(new HistogramItem("王五一",46));
//        mList.add(new HistogramItem("张明雪",43));
//        mList.add(new HistogramItem("镜子",45));
//        mList.add(new HistogramItem("的哭丧家",44));
//        mList.add(new HistogramItem("发到空间撒",13));
//        mList.add(new HistogramItem("打击",24));
//        mList.add(new HistogramItem("的积分卡拉",23));
//        mList.add(new HistogramItem("的快速发",64));
//        mList.add(new HistogramItem("发的康",45));
//        mList.add(new HistogramItem("的境况放",47));
//        mList.add(new HistogramItem("的健身卡",46));
//
//
//    }
    public void setmList(List<HistogramItem> list){
        mList=list;
        requestLayout();//刷新onMeasure方法
        invalidate();//刷新onDraw方法

    }
}

注意点:

  • 在onDraw中获得所画的文字的宽度:画笔paint.measureText(percent).
    这里将文字居中一般的方法就是利用所写的位置剪掉文字长度的一半:
    这里写图片描述

  • 在主活动中将数据mList传给自定义的柱形view,需要在自定义的view中创建一个setmList的方法。(其中需要写requestLayout()【刷新onMesure方法】和invalidate()【刷新onDraw方法】
    这里写图片描述

自定义折线图

  • 效果:
    这里写图片描述
  • 代码:
    自定义LineChartView 类:
package com.example.myapplication.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.view.View;

import com.example.myapplication.model.LineChartItem;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2015/10/9.
 */
public class LineChartView extends View {
    private int height;
    private int width;
    private List<LineChartItem> mList;
    private int lineWidthSpacing = 100;
    private int leftwidth = 30;
    private int rightwidth = 30;
    private int lineWidth = 2;
    private int textWidth = 1;
    private int circleBigR = 5;
    private int circleSmallR = 3;
    private int bottomBarHeight = 80;//低端放文字的高度
    private Paint mPaintBackLine;
    private Paint mPaintLine;
    private Paint mPaintCount;
    private Paint mPaintMonth;
    private Paint mPaintBottomBar;
    private Paint mPaintGridBack;
    private Paint mPaintCircleBig;
    private Paint mPaintCircleSmall;
    private Paint mPaintRect;
    private Path mPathShade;


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

    public LineChartView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //对大圈画笔初始化
        mPaintCircleBig = new Paint();
        mPaintCircleBig.setColor(Color.argb(0xff, 0x1e, 0x90, 0xff));
        mPaintCircleBig.setStyle(Paint.Style.FILL_AND_STROKE);

        //对小圈画笔初始化
        mPaintCircleSmall = new Paint();
        mPaintCircleSmall.setColor(Color.WHITE);
        mPaintCircleSmall.setStyle(Paint.Style.FILL_AND_STROKE);

        //对背景的分隔线画笔进行初始化
        mPaintBackLine = new Paint();
        mPaintBackLine.setColor(Color.argb(0xff, 0x8b, 0x89, 0x89));
        mPaintBackLine.setAntiAlias(true);
        mPaintBackLine.setStrokeWidth(1);

        //对折线,圆圈以及的画笔进行初始化
        mPaintLine = new Paint();
        mPaintLine.setStrokeWidth(lineWidth);
        mPaintLine.setAntiAlias(true);
        mPaintLine.setColor(Color.argb(0xff, 0x1e, 0x90, 0xff));
        mPaintLine.setStyle(Paint.Style.STROKE);

        //对count标字的画笔的初始化
        mPaintCount = new Paint();
        mPaintCount.setStrokeWidth(textWidth);
        mPaintCount.setAntiAlias(true);
        mPaintCount.setColor(Color.argb(0xff, 0x1e, 0x90, 0xff));
       // mPaintCount.setTextAlign(Paint.Align.CENTER);

        //对月份画笔进行初始化
        mPaintMonth = new Paint();
        mPaintMonth.setColor(Color.BLACK);
        mPaintMonth.setAntiAlias(true);
        mPaintCount.setStrokeWidth(textWidth);

        //低端文字区域画笔初始化
        mPaintBottomBar = new Paint();
        mPaintBottomBar.setColor(Color.WHITE);
        mPaintBottomBar.setAntiAlias(true);
        mPaintBottomBar.setTextAlign(Paint.Align.CENTER);

        //网格的背景色护臂初始化
        mPaintGridBack  = new Paint();
        mPaintGridBack.setColor(Color.argb(0xff, 0xdb, 0xdb, 0xdb));

        //对阴影的画笔初始化
        mPaintRect = new Paint();
        mPaintRect.setColor(Color.argb(0xff, 0x1e, 0x90, 0xff));
        mPaintRect.setAlpha(50);
        mPaintRect.setStyle(Paint.Style.FILL);

        mPathShade = new Path();


        //做特效添加阴影
        PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP);//必须设置在上面的控件
        mPaintRect.setXfermode(mode);

    }

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if(mList==null){
            width=   getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        }else {
            width = (int) (mList.size() * lineWidthSpacing);
        }
        height=getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);
        //init();


    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawRect(0, 0, width, height - bottomBarHeight, mPaintGridBack);
        canvas.drawRect(0, height - bottomBarHeight, width, height, mPaintBottomBar);

        //画背景分隔线的横线
        for (int i = 0;i < 5;i ++){
            canvas.drawLine(leftwidth,i*((height-bottomBarHeight)/4),leftwidth + (mList.size()-1) * lineWidthSpacing,i*((height-bottomBarHeight)/4),mPaintBackLine);
        }
        for(int i = 0 ;i < mList.size() ;i++){
            //画背景分隔线的竖线
            canvas.drawLine(leftwidth + i * lineWidthSpacing, 0, leftwidth + i * lineWidthSpacing, height-bottomBarHeight, mPaintBackLine);

        }
        //画连线
        for (int i=0;i<mList.size()-1;i++){
            LineChartItem item = mList.get(i);
            float count = item.getCount();
            float nextcount = mList.get(i+1).getCount();
            canvas.drawLine(leftwidth+i*lineWidthSpacing,(height-bottomBarHeight)-(height-bottomBarHeight)*count/40,leftwidth+(i+1)*lineWidthSpacing,(height-bottomBarHeight)-(height-bottomBarHeight)*nextcount/40,mPaintLine);
        }

        //画阴影
        mPathShade.reset();
        mPathShade.moveTo(leftwidth, height -bottomBarHeight);
        for(int i = 0 ;i < mList.size() ;i++){
            LineChartItem item = mList.get(i);
            float count = item.getCount();
            mPathShade.lineTo(leftwidth+i*lineWidthSpacing,(height-bottomBarHeight)-(height-bottomBarHeight)*count/40);

        }
        mPathShade.lineTo(leftwidth + (mList.size() - 1) * lineWidthSpacing, height -bottomBarHeight);
        mPathShade.close();
        canvas.drawPath(mPathShade,mPaintRect);



        for(int i = 0 ;i < mList.size() ;i++){
            LineChartItem item = mList.get(i);
            int month = item.getCalender();
            float count = item.getCount();
            //画每个数据的小圆圈
            canvas.drawCircle(leftwidth+i*lineWidthSpacing,(height-bottomBarHeight)-(height-bottomBarHeight)*count/40, circleBigR,mPaintCircleBig);
            canvas.drawCircle(leftwidth+i*lineWidthSpacing,(height-bottomBarHeight)-(height-bottomBarHeight)*count/40, circleSmallR,mPaintCircleSmall);

            //画count
            canvas.drawText("" + count, leftwidth + i * lineWidthSpacing-mPaintCount.measureText(count+"")/2, (height - bottomBarHeight) - (height - bottomBarHeight) * count / 40 - circleBigR - 10, mPaintLine);
            //画月份
            if(i<10) {
                String newmonth = "0" + month;
                canvas.drawText(newmonth, leftwidth + i * lineWidthSpacing-mPaintMonth.measureText(newmonth)/2, height - bottomBarHeight / 2, mPaintMonth);
            }else {
                String newnewmonth = ""+month;
                canvas.drawText(newnewmonth, leftwidth + i * lineWidthSpacing-mPaintMonth.measureText(newnewmonth)/2, height - bottomBarHeight / 2, mPaintMonth);


            }

        }


    }

    public void setmList(List<LineChartItem> list){
        mList=list;
        requestLayout();//刷新onMeasure方法
        invalidate();//刷新onDraw方法

    }
}

两个自定义view资源下载:
http://download.csdn.net/detail/womengmengyan/9178355

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值