用途说明:

这是一个自定义的圆环图像,支持动画展示,可以自定义圆环的颜色和占比,主要用以展示一些数据占比方面展示的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”。

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

更多相关文章

  1. 一句话锁定MySQL数据占用元凶
  2. android android 在list view中插入一条广告
  3. 跟Google学习Android开发-起始篇-保存数据(2)
  4. 分享这近做的一款android软件-"妞妞驾考"
  5. Android2018年最新前沿框架和技术
  6. android 上面一个listview下面一个button,让button一直处于listv
  7. 摄像头Camera视频源数据采集解析
  8. 基于Android的英文电子词典
  9. Android(安卓)收发彩信(MMS)

随机推荐

  1. Android中的Intent详解
  2. 【Android】Android背景选择器selector用
  3. Java/Android引用类型及其使用分析
  4. Android Activity切换动画overridePendin
  5. org.json.JSONException: End of input a
  6. Android之使用Pull解析Xml数据
  7. android短信服务
  8. Android 里面的android_secret_code
  9. Android ScrollView包裹EditText 软键盘
  10. 获取应用签名