博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 实现自定义圆环
阅读量:6946 次
发布时间:2019-06-27

本文共 9747 字,大约阅读时间需要 32 分钟。

用途说明:

这是一个自定义的圆环图像,支持动画展示,可以自定义圆环的颜色和占比,主要用以展示一些数据占比方面展示的android圆环。

圆环实现思路:

android的自定义圆环实现有很多种方法,这里只介绍我实现的思路。主要思路是先画一个大圆,然后再画一个与大圆同圆心的小圆,然后小圆的颜色可以设置为背景色,这样看上去就是一个圆环了。

实现效果:

使用方法:

1.布局文件中直接使用自定义圆环(RingView),控件的宽和高需要固定的尺寸

复制代码

2.在对应的activty中调用一些方法来实现你的需求即可

public class TestActivity extends AppCompatActivity {          @Bind(R.id.rvRingView)          RingView mRvRingView;          @Override          protected void onCreate(@Nullable Bundle savedInstanceState) {                  super.onCreate(savedInstanceState);                  setContentView(R.layout.layout_test1);                 ButterKnife.bind(this);          mRvRingView.setAnglesData("12.2","230","6799.01","1","111","200");//直接设置String类型的数据//        mRvRingView.setAnglesData(12.2,230,6799.01,1,111,200);//直接设置double类型的数据//        mRvRingView.setAngles(20, 40, 100, 180, 20);//设置的是角度           //       mRvRingView.setRingStartAngle(-90);//设置圆环的开始角度,不设置默认是-90                 //设置画笔的颜色,支持字符串和资源文件可变参数。                    mRvRingView.initPaint("#123456", "#fea123", "#fefefe", "#78da10", "#1121de", "#aacc18");//支持字符串//        mRvRingView.initPaint(R.color.color_first_part,R.color.color_second_part,//                             R.color.color_third_part,R.color.color_fourth_part,//                             R.color.color_fifth_part,R.color.color_sixth_part);//        mRvRingView.setInnerCirclePaintColor("#ffffff");//内圆的画笔颜色,默认#ffffff              mRvRingView.setRingStrokeWidth(40);//圆环的环宽,默认20//        mRvRingView.showViewWithAnimation(1000);//自定义动画时长展示圆环//        mRvRingView.showViewWithoutAnimation();//展示圆环不带动画             mRvRingView.showViewWithAnimation();//动画展示圆环,默认2s          }}复制代码

3.自定义view的源码

public class RingView extends View {        private static final int CIRCLE_ANGLE = 360;//圆环的角度        private static final int RING_STROKE_WIDTH = 20;//默认圆环的宽度为20dp        private Paint mNoAssetsPaint, mInnerCirclePaint;        private ArrayList
mPaints; private int mRingStrokeWidth;//圆环的宽度 private int mCanvasWidth, mCanvasHeight; private RectF mRingRect, mInnerRect; private int mDensity;//手机屏幕密度 private int mNoDataPaintColor = Color.parseColor("#cccccc");//没有数据的paint的颜色 private int mInnerCirclePaintColor = Color.parseColor("#ffffff");//内圆的paint的颜色 private ArrayList
mAngles;//传入的数据 private boolean mHasData = false; private ArrayList
mLevelStartAngles;//每段圆弧的起始角度值 private int mMoveAngle;//圆弧移动的角度 private int mRingStartAngle = -90;//圆环的起始角度 private RingAnimation mRingAnim; public RingView(Context context) { super(context); init(context); } public RingView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public RingView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context ctx) { mDensity = (int) ctx.getResources().getDisplayMetrics().density; mRingStrokeWidth = RING_STROKE_WIDTH * mDensity; mPaints = new ArrayList
(); mAngles = new ArrayList
(); mLevelStartAngles = new ArrayList
(); mNoAssetsPaint = new Paint(); mNoAssetsPaint.setAntiAlias(true); mNoAssetsPaint.setStyle(Paint.Style.FILL); mNoAssetsPaint.setColor(mNoDataPaintColor); mInnerCirclePaint = new Paint(); mInnerCirclePaint.setAntiAlias(true); mInnerCirclePaint.setStyle(Paint.Style.FILL); mInnerCirclePaint.setColor(mInnerCirclePaintColor); mRingAnim = new RingAnimation(); } @Override protected void onDraw(Canvas canvas) { if (mCanvasWidth == 0) { initRect(); } if (!mHasData) {//没有数据 mMoveAngle = CIRCLE_ANGLE; drawRingView(canvas, mRingStartAngle, mMoveAngle, mNoAssetsPaint); } else { int _level = 0;//圆弧的段数 for (int _i = 0; _i < mAngles.size(); _i++) {//计算需要画几段圆弧 if (mMoveAngle < mLevelStartAngles.get(1)) { _level = 1; } else if (mMoveAngle > mLevelStartAngles.get(_i) && mMoveAngle <= mLevelStartAngles.get(_i + 1)) { _level = _i + 1; } } drawRing(_level, canvas); } canvas.drawArc(mInnerRect, mRingStartAngle, CIRCLE_ANGLE, true, mInnerCirclePaint);//画内部的圆 } /** * * @param level 圆环的段数 * @param canvas */ private void drawRing(int level, Canvas canvas) { if (level <= 0) { drawRingView(canvas, mRingStartAngle, CIRCLE_ANGLE, mNoAssetsPaint); return; } if (mAngles.size() > mPaints.size()) { int _temp = mAngles.size() - mPaints.size(); for (int _i = 0; _i < _temp; _i++) { mPaints.add(mNoAssetsPaint); } } for (int _i = 0; _i < level; _i++) { if (_i == level - 1) { drawRingView(canvas, mRingStartAngle + mLevelStartAngles.get(_i), mMoveAngle - mLevelStartAngles.get(_i), mPaints.get(_i)); } else { drawRingView(canvas, mRingStartAngle + mLevelStartAngles.get(_i), mAngles.get(_i), mPaints.get(_i)); } } } /** * * @param canvas * @param startAngle 开始的角度 * @param sweepAngle 旋转的角度 * @param paint 画笔 */ private void drawRingView(Canvas canvas, int startAngle, int sweepAngle, Paint paint) { if (sweepAngle != 0) { canvas.drawArc(mRingRect, startAngle, sweepAngle, true, paint); } } public void setNoDataPaintColor(int color) { mNoAssetsPaint.setColor(getResources().getColor(color)); } public void setNoDataPaintColor(String color) { mNoAssetsPaint.setColor(Color.parseColor(color)); } public void setInnerCirclePaintColor(int colorId) { mInnerCirclePaint.setColor(getResources().getColor(colorId)); } public void setInnerCirclePaintColor(String color){ mInnerCirclePaint.setColor(Color.parseColor(color)); } public void initPaint(ArrayList
colors) { mPaints.clear(); for (int _i = 0; _i < colors.size(); _i++) { Paint _paint = new Paint(); _paint.setAntiAlias(true); _paint.setStyle(Paint.Style.FILL); _paint.setColor(colors.get(_i)); mPaints.add(_paint); } } public void initPaint(String... colors) { ArrayList
_colors = new ArrayList
(); for (int _i = 0; _i < colors.length; _i++) { _colors.add(Color.parseColor(colors[_i])); } initPaint(_colors); } public void initPaint(int... colorIds) { ArrayList
_colors = new ArrayList
(); for (int _i = 0; _i < colorIds.length; _i++) { _colors.add(getResources().getColor(colorIds[_i])); } initPaint(_colors); } private void initRect() { mCanvasWidth = getWidth(); mCanvasHeight = getHeight(); mInnerRect = new RectF(mRingStrokeWidth, mRingStrokeWidth, mCanvasWidth - mRingStrokeWidth, mCanvasHeight - mRingStrokeWidth); mRingRect = new RectF(0, 0, mCanvasWidth, mCanvasHeight); } /** * 设置圆环起始的角度 * @param angle */ public void setRingStartAngle(int angle){ mRingStartAngle = angle; } /** * 设置圆环的环宽 * * @param width */ public void setRingStrokeWidth(int width) { mRingStrokeWidth = width * mDensity; invalidate(); } /** * 所需要显示的数据的角度 * * @param angles */ public void setAngles(int... angles) { ArrayList
_angles = new ArrayList
(); for (int _i = 0; _i < angles.length; _i++) { _angles.add(angles[_i]); } setAngles(_angles); } /** * 所需要显示的数据的角度 * * @param angles */ public void setAngles(ArrayList
angles) { mAngles.clear(); mAngles.addAll(angles); mLevelStartAngles.clear(); mLevelStartAngles.add(0); int _angle = 0; for (int _i = 0; _i < mAngles.size(); _i++) { _angle += mAngles.get(_i); mLevelStartAngles.add(_angle); if (mAngles.get(_i) > 0) { mHasData = true; } } } /** * 设置数据来计算角度并绘制圆环 * * @param data */ public void setAnglesData(BigDecimal... data) { BigDecimal _total = new BigDecimal("0.00"); for (int _i = 0; _i < data.length; _i++) { _total = _total.add(data[_i]); } if (_total.compareTo(BigDecimal.valueOf(0)) == 0) { mHasData = false; return; } BigDecimal[] _dbData = new BigDecimal[data.length]; for (int _i = 0; _i < data.length; _i++) { _dbData[_i] = data[_i].divide(_total, 10, ROUND_HALF_UP).multiply(BigDecimal.valueOf(360)); } int[] _intData = new int[data.length]; for (int _i = 0; _i < data.length; _i++) { //数值小于1且大于0的,就直接定1,否则转int类型,确保小数据也能出现在圆环上 _intData[_i] = _dbData[_i].compareTo(BigDecimal.valueOf(1.0)) < 0 && _dbData[_i].compareTo(BigDecimal.valueOf(0)) > 0 ? 1 : _dbData[_i].intValue(); } //所有数据加起来可能会不满360也可能会超出360,由于精度的问题 //处理方案是把缺少的度数(有正也有负)加在最大的值上,这样图形出现的误差会不明显 int _remind = 360;//剩余的角度 int _maxPosition = -1, _max = _intData[0]; for (int _i = 0; _i < _intData.length; _i++) { _remind = _remind - _intData[_i]; if (_max <= _intData[_i]) { _maxPosition = _i; } } _intData[_maxPosition] += _remind;//将缺少的度数加载最大值上 //将最终的数据设置到圆环上 setAngles(_intData); } public void setAnglesData(String... data) { BigDecimal[] _bdData = new BigDecimal[data.length]; for (int _i = 0; _i < data.length; _i++) { _bdData[_i] = new BigDecimal(TextUtils.isEmpty(data[_i]) ? "0" : data[_i]); } setAnglesData(_bdData); } public void setAnglesData(double... data) { BigDecimal[] _bdData = new BigDecimal[data.length]; for (int _i = 0; _i < data.length; _i++) { _bdData[_i] = BigDecimal.valueOf(data[_i]); } setAnglesData(_bdData); } /** * 自定义动画时间的圆环 * * @param animTime */ public void showViewWithAnimation(int animTime) { startAnimation(animTime); } /** * 默认时间(2000)的圆环 */ public void showViewWithAnimation() { startAnimation(-1); } /** * 不带动画的圆环 */ public void showViewWithoutAnimation() { mMoveAngle = CIRCLE_ANGLE; invalidate(); } private void startAnimation(int animTime) { mRingAnim.setDuration(animTime <= 0 ? 2000 : animTime); startAnimation(mRingAnim); } private class RingAnimation extends Animation { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { mMoveAngle = (int) (interpolatedTime * CIRCLE_ANGLE); invalidate(); } }}复制代码

4.代码实现的一些注意点

1)控件的宽和高必须是固定的,不然无法显示。 2)画笔颜色的数组长度必须大于或等于数据数组的长度,不然超出的数据将由默认的没有数据的颜色显示。 3)在设置画笔颜色时,使用的字符串形式的颜色必须严格遵循颜色的书写方式,不然会出现无法正确显示view。例如:不支持“#fff”,支持“#ffffff”。

该控件中还存在很多需要优化的地方和更多的功能支持,后期会补充,希望各位大神可以给出指导性的意见和建议,十分感谢?。

转载地址:http://llonl.baihongyu.com/

你可能感兴趣的文章
设置ToggleButton、Switch、CheckBox和RadioButton的显示效果
查看>>
EntityManager常用API
查看>>
bower提交自己的类库
查看>>
Swift - 使用CoreLocation实现定位(经纬度、海拔、速度、距离等)
查看>>
Netty 编码解码框架
查看>>
.NET程序员学PHP要注意的坑
查看>>
windows下的fltk之编译以及试运行
查看>>
js提示框
查看>>
为什么关系型数据库不适于Hadoop
查看>>
换种角度解决问题
查看>>
功能测试报告
查看>>
JFinal-Beetl-Shiro(JdbcRealm)-例子
查看>>
跬步之积,以至千里
查看>>
[转]关于java文件读写、字节流、字符流的一点新得
查看>>
常量池、栈、堆的比较
查看>>
centos下载地址
查看>>
php防止模拟请求
查看>>
Javascript 控制 CheckBox 的全选与取消全选
查看>>
推荐编程书记书籍
查看>>
JVM系列一:JVM内存组成及分配
查看>>