Description of use:

This is a custom ring image, support animation display, you can customize the ring color and proportion, mainly used to show some data proportion of the android ring display.

Circle realization idea:

Android custom circle implementation there are many methods, here I only introduced the idea of implementation. The main idea is to draw a big circle first, and then draw a small circle with the same center as the big circle, and then the color of the small circle can be set to the background color, so that it looks like a circle.

Effect:

Usage:

1. The layout file directly uses the custom ring (RingView). The width and height of the control need to be fixed

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"       
       android:layout_width="match_parent"    
       android:layout_height="match_parent"    
       android:background="@android:color/white"    
       android:orientation="vertical">    

       <com.wuden.zxingproject.widgets.RingView        
                android:id="@+id/rvRingView"        
                android:layout_gravity="center"        
                android:layout_width="300dp"        
                android:layout_height="300dp" />
</LinearLayout>
Copy the code

2. Call some methods in the corresponding Activty to realize your requirements

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"); Direct set of type String data / / / / mRvRingView setAnglesData (12.2, 9.01, 230679, 1111200); // mrvringview.setangles (20, 40, 100, 180, 20); // Mrvringview.setangles (20, 40, 100, 180, 20); . / / / / set is Angle mRvRingView setRingStartAngle (90); // Set the starting Angle of the ring. Default is -90. // Set the color of the brush. mRvRingView.initPaint("# 123456"."#fea123"."#fefefe"."#78da10"."#1121de"."#aacc18"); 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"); // Brush color for inner circle, default#ffffff    mRvRingView.setRingStrokeWidth(40); / / ring ring width, the default 20 / / mRvRingView showViewWithAnimation (1000); Long show ring / / / / custom animation mRvRingView. ShowViewWithoutAnimation (); / / show ring not by mRvRingView showViewWithAnimation (); // animation shows the circle, default 2s}}Copy the code

3. Custom view source code

public class RingView extends View { private static final int CIRCLE_ANGLE = 360; Private static final int RING_STROKE_WIDTH = 20; Private Paint mNoAssetsPaint, mInnerCirclePaint; private ArrayList<Paint> mPaints; private int mRingStrokeWidth; Private int mCanvasWidth, mCanvasHeight; private RectF mRingRect, mInnerRect; private int mDensity; Private int mNoDataPaintColor = color.parsecolor (private int mNoDataPaintColor = color.parsecolor ("#cccccc"); Private int mInnerCirclePaintColor = color.parsecolor (private int mInnerCirclePaintColor = color.parsecolor ("#ffffff"); Private ArrayList<Integer> mAngles; Private Boolean mHasData =false; private ArrayList<Integer> mLevelStartAngles; Private int mMoveAngle; private int mMoveAngle; Private int mRingStartAngle = -90; 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<Paint>(); mAngles = new ArrayList<Integer>(); mLevelStartAngles = new ArrayList<Integer>(); 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) {// No data mMoveAngle = CIRCLE_ANGLE; drawRingView(canvas, mRingStartAngle, mMoveAngle, mNoAssetsPaint); }else{ int _level = 0; // The segment number of the arcfor(int _i = 0; _i < mAngles.size(); _i++) {// The calculation requires drawing several arcsif (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); Private void drawRing(int level, canvas 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 Angle * @param sweepAngle Angle rotated * @param paint brush */ 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<Integer> 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<Integer> _colors = new ArrayList<Integer>();
        for (int _i = 0; _i < colors.length; _i++) {
            _colors.add(Color.parseColor(colors[_i]));
        }
        initPaint(_colors);
    }

    public void initPaint(int... colorIds) {
        ArrayList<Integer> _colors = new ArrayList<Integer>();
        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); } /** * set the start Angle of the circle * @param Angle */ public voidsetRingStartAngle(int angle){ mRingStartAngle = angle; } /** * @param width */ public voidsetRingStrokeWidth(int width) { mRingStrokeWidth = width * mDensity; invalidate(); } /** * @param angles */ public voidsetAngles(int... angles) {
        ArrayList<Integer> _angles = new ArrayList<Integer>();
        for (int _i = 0; _i < angles.length; _i++) {
            _angles.add(angles[_i]);
        }
        setAngles(_angles); } /** * @param angles */ public voidsetAngles(ArrayList<Integer> 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; }} /** * set the data to calculate the Angle and draw the circle ** @param data */ public voidsetAnglesData(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++) {// If the value is less than 1 and greater than 0, set it to 1. Ensure that small data can also appear on the ring _intData[_i] = _dbData[_I]. CompareTo (BigDecimal.valueof (1.0)) < 0 && _dbData[_i].compareTo(BigDecimal.valueOf(0)) > 0 ? 1 : _dbData[_i].intValue(); } int _remind = 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; // Load the missing degree to the maximum value // Set the final data to the ringsetAngles(_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); } /** * Default time (2000) circle */ public voidshowViewWithAnimation() { 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(floatinterpolatedTime, Transformation t) { mMoveAngle = (int) (interpolatedTime * CIRCLE_ANGLE); invalidate(); }}}Copy the code

4. Some points to note about code implementation

1) The width and height of the control must be fixed, otherwise it cannot be displayed. 2) The length of the brush color array must be greater than or equal to the length of the data array, otherwise the excess data will be displayed by the default color without data. 3) When setting the color of the brush, the color in the form of string must strictly follow the writing mode of the color, otherwise the view will not be displayed correctly. For example, # FFFFFF is supported instead of # FFF.

The control also has a lot of need to optimize the place and more functional support, later will be supplemented, I hope you can give guiding opinions and suggestions, very thank 🙏.