Android 扇形统计图
先看看效果:
看上去如果觉得还行就继续往下看吧!
自定义View
定义成员变量
private int mHeight, mWidth;//宽高 private Paint mPaint;//扇形的画笔 private Paint mTextPaint;//画文字的画笔 private int centerX, centerY;//中心坐标 //"其他"的value //扇形图分成太多快 所以要合并一部分为其他 即图中灰色部分 private double rest; private int maxNum = 5;//扇形图的最大块数 超过的item就合并到其他 String others = "其他";//“其他”块要显示的文字 double total;//数据的总和 double[] datas;//数据集 String[] texts;//每个数据对应的文字集 //颜色 默认的颜色 private int[] mColors = { Color.parseColor("#FF4081"), Color.parseColor("#ffc0cb"), Color.parseColor("#00ff00"), Color.parseColor("#0066ff"), Color.parseColor("#ffee00") }; private int mTextSize;//文字大小 单位:像素 private int radius = 1000;//半径 在画图时初始化
测量宽高
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //获取宽高 不要设置wrap_content mHeight = MeasureSpec.getSize(heightMeasureSpec); mWidth = MeasureSpec.getSize(widthMeasureSpec); }
画图
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //无数据 直接返回 if (datas == null || datas.length == 0) return; centerX = (getRight() - getLeft()) / 2; centerY = (getBottom() - getTop()) / 2; int min = mHeight > mWidth ? mWidth : mHeight; if (radius > min / 2) { radius = (int) ((min - getPaddingTop() - getPaddingBottom()) / 3.5); } //画各个扇形 drawCircle(canvas); //画线与文字 drawLineAndText(canvas); }
画扇形
一个圆形统计图是由许多个扇形组成的,我们根据数据计算出每个扇形的角度即可。注意,画弧度的时候,角度是顺时针变大的!即与我们平时的坐标是反过来的
//画扇形 private void drawCircle(Canvas canvas) { int centerX =( getRight() - getLeft() )/2;//中点 int centerY = ( getBottom() - getTop()) /2; RectF rect = new RectF((float) (centerX - radius), centerY-radius, centerX+radius,centerY+radius);//圆形区域 int start = 0;//扇形开始的角度 for (int i = 0; i < (maxNum<datas.length?maxNum:datas.length); i++) { float angles = (float) ((datas[i] * 1.0f /total) * 360);//计算扇形的角度 mPaint.setColor(mColors[i%mColors.length]);//颜色 canvas.drawArc(rect,start,angles,true,mPaint);//画扇形 start += angles;//下一个扇形开始的角度 } //画"其他"部分 即图中灰色的部分 rest =0;//保存其他部分的value for(int i=maxNum;i<datas.length;i++){ rest+=datas[i]; } float angles = (float) 360 - start;//角度 mPaint.setColor(Color.GRAY); canvas.drawArc(rect,start,angles,true,mPaint); }
画线条和文字
主要是计算各个点的坐标很烦
这里我画出一个图 大家把代码和图对照理解一下
//画线与文字 private void drawLineAndText(Canvas canvas) { int start = 0; //平移画布到中心 所以下面的坐标是从中点开始算起的 canvas.translate(centerX, centerY); mPaint.setStrokeWidth(4);//线条宽度 //如果数据集过大 那么要合并到其他 for (int i = 0; i < (maxNum < datas.length ? maxNum : datas.length); i++) { float angles = (float) ((datas[i] * 1.0f / total) * 360); //画线条和文字 drawLine(canvas, start, angles, texts[i], mColors[i % mColors.length]); start += angles; } //画其他部分的线条和文字 if (start < 360)//如果start小于360 说明有其他部分 drawLine(canvas, start, 360 - start, others, Color.GRAY); } private void drawLine(Canvas canvas, int start, float angles, String text, int color) { mPaint.setColor(color); float stopX, stopY; stopX = (float) ((radius + 40) * Math.cos((2 * start + angles) / 2 * Math.PI / 180)); stopY = (float) ((radius + 40) * Math.sin((2 * start + angles) / 2 * Math.PI / 180)); canvas.drawLine((float) ((radius - 20) * Math.cos((2 * start + angles) / 2 * Math.PI / 180)), (float) ((radius - 20) * Math.sin((2 * start + angles) / 2 * Math.PI / 180)), stopX, stopY, mPaint ); //画横线 int dx;//判断横线是画在左边还是右边 int endX; if (stopX > 0) { endX = (centerX - getPaddingRight() - 20); } else { endX = (-centerX + getPaddingLeft() + 20); } //画横线 canvas.drawLine(stopX, stopY, endX, stopY, mPaint ); dx = (int) (endX - stopX); //测量文字大小 Rect rect = new Rect(); mTextPaint.getTextBounds(text, 0, text.length(), rect); int w = rect.width(); int h = rect.height(); int offset = 20;//文字在横线的偏移量 //画文字 文字的Y坐标值的是文字底部的Y坐标 canvas.drawText(text, 0, text.length(), dx > 0 ? stopX + offset : stopX - w - offset, stopY + h, mTextPaint); //测量百分比大小 String percentage = angles / 3.60 + ""; percentage = percentage.substring(0, percentage.length() > 4 ? 4 : percentage.length()) + "%"; mTextPaint.getTextBounds(percentage, 0, percentage.length(), rect); w = rect.width() - 10; //画百分比 canvas.drawText(percentage, 0, percentage.length(), dx > 0 ? stopX + offset : stopX - w - offset, stopY - 5, mTextPaint); }
这样我们就已经完成了绘制的工作了,接下来就是绑定数据啦!
大家只要把datas和texts填充好数据就可以啦,最好调用一下invalidate()方法请求重绘(如果已经绘制了)。
我使用了一个内部抽象类来实现数据绑定的:
public abstract class ArcViewAdapter<T> { public void setData(List<T> list) { datas = new double[list.size()]; texts = new String[list.size()]; for (int i = 0; i < list.size(); i++) { total += getValue(list.get(i)); datas[i] = getValue(list.get(i)); texts[i] = getText(list.get(i)); } invalidate();//请求重绘 } //通过传来的数据集的某个元素 得到具体的数字 public abstract double getValue(T t); //通过传来的数据集的某个元素 得到具体的描述 public abstract String getText(T t); }
在布局文件里面引用这个ArcView,然后在MainActivity中绑定数据:
ArcView arcView = (ArcView) findViewById(R.id.arc); List<Times> times = new ArrayList<>(); for (int i = 6; i > 0; i--) { Times t = new Times();//这个类就只有两个变量 t.hour = i; t.text = "Number"+i; times.add(t); } //初始化适配器 ArcView.ArcViewAdapter myAdapter = arcView.new ArcViewAdapter<Times>(){ @Override public double getValue(Times times) { return times.hour; } @Override public String getText(Times times) { return times.text; } }; myAdapter.setData(times);//绑定数据
大家可以设置各种setter以便在Activity中调用,来提高ArcView的灵活性,比如设置颜色、半径、最大块数等等。
demo下载地址:SectorDiagram_jb51.rar
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
本文向大家介绍Android 自定义View之倒计时实例代码,包括了Android 自定义View之倒计时实例代码的使用技巧和注意事项,需要的朋友参考一下 Android 自定义View之倒计时实例代码 需求: 大多数app在注册的时候,都有一个获取验证码的按钮,点击后,访问接口,最终用户会收到短信验证码。为了不多次写这个获取验证码的接口,下面将它自定义成一个view,方便使用。 分析一下,这是一
绘制自定义形状-扇形 感谢群友 墨明棋妙 309764601@qq.com 提供功能思路和源码 目前cesium的entity里面是没有直接绘制扇形的形状的,当时在网上搜索的时候,在官方的google group里面有人明确说明是没有的,然后需要自己重载Geometry,再重新打包。。。 这,略麻烦,然后墨明棋妙兄弟就自己写了一个函数来进行绘制,最终提供了源码,感谢感谢 思路比较简单,如下: 1.
本文向大家介绍Android自定义View圆形图片控件代码详解,包括了Android自定义View圆形图片控件代码详解的使用技巧和注意事项,需要的朋友参考一下 前言 在日常开发中,圆形的图片效果还是很常见的。可以通过给Paint设置Xfermode来实现,这里简单记录如下。 实现 实现圆形效果的核心是PorterDuffXfermode,对于PorterDuffXfermode,这里不展开,可以查
本文向大家介绍Android自定义View实现折线图效果,包括了Android自定义View实现折线图效果的使用技巧和注意事项,需要的朋友参考一下 下面就是结果图(每种状态用一个表情图片表示): 一、主页面的布局文件如下: 其中linecharview就是自定义的View,而app:xx就是这个View的各种属性。 二、在values的attrs文件中加入如下xml,来定义linecharview
本文向大家介绍Android自定义View实现验证码,包括了Android自定义View实现验证码的使用技巧和注意事项,需要的朋友参考一下 本文章是基于鸿洋的Android 自定义View (一) 的一些扩展,以及对Android自定义View构造函数详解里面内容的一些转载。 首先我们定义一个declare-styleable标签declare-styleable标签的作用是给自定义控件添加自定义
本文向大家介绍Android自定义view实现太极效果实例代码,包括了Android自定义view实现太极效果实例代码的使用技巧和注意事项,需要的朋友参考一下 Android自定义view实现太极效果实例代码 之前一直想要个加载的loading。却不知道用什么好,然后就想到了太极图标,最后效果是有了,不过感觉用来做loading简直丑到爆!!! 实现效果很简单,我们不要用什么贝塞尔曲线啥的,因为太