Android 红圈营销项目 —— 自定义柱形图和自定义折线图
2015-10-13 20:32
579 查看
自定义柱形图
效果:- 代码:
自定义柱形图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
相关文章推荐
- Android M版本和非M版本动态权限适配方案
- Android 4.2 Wifi Display 之 Settings 源码分析(一)
- android Intent机制详解
- Android_01_点击事件中View对象的作用
- Android_01_短信发送器
- 摘抄一篇文章android中LinearLayout中layout_weight详解
- Android内存管理知识
- android listview 取消头部分割线
- 坚持坚持坚持
- Android activity的生命周期
- 【Android】【编译】Android 编译相关
- 【Android】【编译】Android 编译相关
- 【Android】【编译】Android 编译相关
- 【Android】【编译】Android 编译相关
- 【Android】【编译】Android 编译相关
- 【Android】【编译】Android 编译相关
- 【Android】【编译】Android 编译相关
- 深入Android&nbsp;MediaPlayer的使用方…
- Android&nbsp;中的&nbsp;Service&nbsp;全面总结
- Android ContentProvid