用途说明:

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

圆环实现思路:

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

实现效果:

动画效果

使用方法:

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

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@android:color/white"

android:orientation="vertical">

android:id="@+id/rvRingView"

android:layout_gravity="center"

android:layout_width="300dp"

android:layout_height="300dp" />

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”。

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

Android 自定义 圆环,Android 实现自定义圆环相关推荐

  1. Android 自定义 圆环,Android自定义view实现圆环效果实例代码

    先上效果图,如果大家感觉不错,请参考实现代码. 重要的是如何实现自定义的view效果 (1)创建类,继承view,重写onDraw和onMesure方法 public class CirclePerc ...

  2. android自定义渐变色圆环,CircleShape渐变颜色圆环

    设计思路 通过自定义控件实现.将整个圆环拆分成一个个的小圆弧,每个小圆弧画笔的色值不一样,每个圆弧画笔的色值都是起始色值和终止色值的中间过渡色,由起始色值逐渐向终止色值靠拢,最后形成渐变颜色的圆环. ...

  3. Android 自定义 圆环,Android自定义View之酷炫圆环(二)

    先看下最终的效果 静态: 动态: 一.开始实现 新建一个DoughnutProgress继承View public class DoughnutProgress extends View { } 先给 ...

  4. android自定义渐变色圆环,Android实现渐变圆环、圆形进度条效果

    最近做了一个功能,里面涉及到了渐变圆形的需求.就是一个颜色可以渐变的圆环,最后实现的效果如下图: 左图是带渐变效果,右图是不带渐变效果.原理还是绘图,Canvas可以绘制的对象有:弧线(arcs).填 ...

  5. android drawable 比例,Android中的Drawable基础与自定义Drawable

    转载请注明链接:http://blog..net/feather_wch/article/details/79124608 本文要点: 1. 介绍Android中Drawable的相关知识点,并且介绍 ...

  6. android自定义笑脸,Android 加载笑脸/哭脸动画

    由于项目要求,需要写一个加载动画,正在加载的时候转圈,加载成功后出现笑脸,加载失败后出现哭脸,于是写了个自定义view,现在贴出来 public class FaceView extends View ...

  7. android仿微博头像_Android 自定义 View 集锦|自定义圆形旋转进度条,仿微博头像加载效果...

    微博 App 的用户头像有一个圆形旋转进度条的加载效果,看上去效果非常不错,如图所示: 据说 Instagram 也采用了这种效果.最近抽空研究了一下,最后实现的效果是这样: 基本上能模拟出个大概,代 ...

  8. android炫酷的自定义view,Android自定义View实现炫酷进度条

    本文实例为大家分享了Android实现炫酷进度条的具体代码,供大家参考,具体内容如下 下面我们来实现如下效果: 第一步:创建attrs文件夹,自定义属性: 第二步:自定义View: /** * Cre ...

  9. android单线字体,Android自定义字体

    在main文件夹下,新建assets/fonts文件,添加.otf文件 image.png 字体工具类 import android.app.Application; import android.g ...

最新文章

  1. opencv基础知识-videowriter
  2. 不疯狂的外星人,已疯狂的资本
  3. 化工热力学:第三章 纯流体的热力学性质
  4. 使用threadlocal_何时以及如何使用ThreadLocal
  5. 架构分享--微博架构
  6. numpy将bool值转换成数值
  7. 亲测可用,超详细RabbitMQ消息队列集群配置
  8. SAP License:ABC作业成本法-平行记帐
  9. python的while分支
  10. 搭建个人论坛网站图文教程
  11. 在R语言中显示数学公式
  12. 利用count if()+条件格式突出显示多余的重复值
  13. MATLAB 中的 mod() 函数
  14. 配合屏幕录像专家,又小又清晰!
  15. canvas 画图 android,Android 中的Canvas画图
  16. RPM(软件包管理器)和YUM 软件仓库
  17. opus 源码下载 以及 相关资料
  18. Nacos整合Gateway实现动态路由
  19. [Android]手机短信验证功能
  20. 「解析」Self-Attention 关键点

热门文章

  1. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-6.用户登录(二),token验证
  2. 达人评测 荣耀magic3pro和华为p50pro参数对比哪个好
  3. 【Spring Boot论坛项目实战】3、开发社区核心功能
  4. contains方法。
  5. Linux上安装QQ,ubuntu18.04安装QQ最新简易教程,一分钟安装QQlinux版。
  6. 使用koa创建自己的服务展示html页面
  7. 微信小程序二手书籍交易平台系统设计与实现
  8. 互联网安全架构平台设计之预防XSS攻击
  9. 人气赞那时王者荣耀法核话语权减少,玩者:禅师成远距了
  10. 通信网数据流量压力测试软件,Socket Client Tester(压力测试工具)