Android custom progress bar control --- advanced to advanced

Show results

Advanced custom progress bar

After talking for so many issues, everyone should understand the custom control routines. If you still don’t understand, please review my first five lectures carefully. Each step in it is more careful. Don’t talk nonsense, just upload the code.

Source code analysis

The "five-step" method memorized by heart

Step 1: Create a custom control class (inherited from View)

 

Step 2: Create custom attributes

Here, we won’t analyze which custom attributes are needed, and directly upload the custom attribute file to everyone. Now everyone should have the ability to understand 

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="myProgress">
<!--圆环底色、四种分色-->
        <attr name="bgColor" format="color"/> 
        <attr name="oneColor" format="color"/>
        <attr name="twoColor" format="color"/>
        <attr name="threeColor" format="color"/>
        <attr name="fourColor" format="color"/>
        <attr name="borderWidth" format="dimension"/>
        <attr name="radius" format="dimension"/>
<!--        文字大小、文字颜色-->
        <attr name="progressText" format="string"/>
        <attr name="progressTextSize" format="dimension"/>
        <attr name="progressTextColor" format="color"/>
    </declare-styleable>
</resources>

Step 3: Apply in the layout file 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".app.MainActivity">

    <com.wustyq.senseone.selfView.myProgress
        android:id="@+id/mp_myProgress"
        android:layout_width="180dp"
        android:layout_height="180dp"
        app:bgColor="#99cccccc"
        app:oneColor="#ccdefc"
        app:twoColor="#89b2f8"
        app:threeColor="#4a8af4"
        app:fourColor="#2d77f2"
        app:borderWidth="15dp"
        app:radius="70dp"
        app:progressText="总进度"
        app:progressTextColor="#1b57de"
        app:progressTextSize="20sp"/>
    <Button
        android:id="@+id/bt_test_one"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="点我试试"/>

</LinearLayout>

Step 4: Get the custom attribute value and write the corresponding method 

package com.wustyq.senseone.selfView;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;

import androidx.annotation.Nullable;

import com.wustyq.senseone.R;

public class myProgress extends View {

    private int mBgColor;
    private int mOneColor;
    private int mTwoColor;
    private int mThreeColor;
    private int mFourColor;
    private int mBorderWidth;
    private String mProgressText;
    private int mProgressTextSize;
    private int mProgressTextColor;
    private int mRadius;

    private Paint mBgPaint;
    private Paint mOnePaint;
    private Paint mTwoPaint;
    private Paint mThreePaint;
    private Paint mFourPaint;
    private Paint mProgressPaint;
    private Paint mTextPaint;

    //当前进度
    private float mCurrentProgress = 0.0f;

    public myProgress(Context context) {
        this(context,null);
    }

    public myProgress(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public myProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.myProgress);

        mBgColor = typedArray.getColor(R.styleable.myProgress_bgColor,mBgColor);
        mOneColor = typedArray.getColor(R.styleable.myProgress_oneColor,mOneColor);
        mTwoColor = typedArray.getColor(R.styleable.myProgress_twoColor,mTwoColor);
        mThreeColor = typedArray.getColor(R.styleable.myProgress_threeColor,mThreeColor);
        mFourColor = typedArray.getColor(R.styleable.myProgress_fourColor,mFourColor);
        mBorderWidth = (int) typedArray.getDimension(R.styleable.myProgress_borderWidth,dip2px(mBorderWidth));
        mRadius = (int) typedArray.getDimension(R.styleable.myProgress_radius,mRadius);

        mProgressText = typedArray.getString(R.styleable.myProgress_progressText);
        mProgressTextSize = typedArray.getDimensionPixelSize(R.styleable.myProgress_progressTextSize,sp2px(mProgressTextSize));
        mProgressTextColor = typedArray.getColor(R.styleable.myProgress_progressTextColor,mProgressTextColor);
        //根据颜色获取画笔
        mBgPaint = initPaint(mBgColor);
        mOnePaint = initPaint(mOneColor);
        mTwoPaint = initPaint(mTwoColor);
        mThreePaint = initPaint(mThreeColor);
        mFourPaint = initPaint(mFourColor);
        mProgressPaint = initTextPaint(mProgressTextColor,mProgressTextSize);
        mTextPaint = initTextPaint(Color.parseColor("#000000"),14);

        typedArray.recycle();
    }

    private int sp2px(int sp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,sp,getResources().getDisplayMetrics());
    }

    private float dip2px(int dip) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dip,getResources().getDisplayMetrics());
    }

    private Paint initTextPaint(int TextColor,int textSize) {
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setTextSize(textSize);
        paint.setColor(TextColor);
        return paint;
    }

    private Paint initPaint(int Color) {
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setStrokeWidth(mBorderWidth);
        paint.setColor(Color);
        return paint;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        //保证是正方形
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        setMeasuredDimension(width>height?height:width,width>height?height:width);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制底部文字
        mTextPaint.setTextSize(mProgressTextSize);
        canvas.drawText(mProgressText,getWidth()/2-getTextWidth(mProgressText)/2, (float) (getHeight()/2+getTextHeight(mProgressText)),mTextPaint);
        //绘制基圆
        drawBgCircle(canvas);
        //获取进度文字
        String currentProgressString =(int) (mCurrentProgress*100) + "%";
        if (mCurrentProgress >= 0.0f && mCurrentProgress <= 0.25f){
            canvas.drawText(currentProgressString,getWidth()/2-getTextWidth(currentProgressString)/2,
                    (float) (getHeight()/2-getTextHeight(currentProgressString)*0.5),mProgressPaint);
            drawArc(canvas,mOnePaint,0,360*mCurrentProgress);
        }else if (mCurrentProgress > 0.25f && mCurrentProgress <= 0.5f){
            canvas.drawText(currentProgressString,getWidth()/2-getTextWidth(currentProgressString)/2,
                    (float) (getHeight()/2-getTextHeight(currentProgressString)*0.5),mProgressPaint);
            drawArc(canvas,mOnePaint,0,90);
            drawArc(canvas,mTwoPaint,90, (float) (360*(mCurrentProgress - 0.25)));
        }else if (mCurrentProgress > 0.5f && mCurrentProgress <= 0.75f){
            canvas.drawText(currentProgressString,getWidth()/2-getTextWidth(currentProgressString)/2,
                    (float) (getHeight()/2-getTextHeight(currentProgressString)*0.5),mProgressPaint);
            drawArc(canvas,mOnePaint,0,90);
            drawArc(canvas,mTwoPaint,90, 90);
            drawArc(canvas,mThreePaint,180,(float) (360*(mCurrentProgress - 0.5)));
        }else if (mCurrentProgress > 0.75f && mCurrentProgress <= 1.0f){
            canvas.drawText(currentProgressString,getWidth()/2-getTextWidth(currentProgressString)/2,
                    (float) (getHeight()/2-getTextHeight(currentProgressString)*0.5),mProgressPaint);
            drawArc(canvas,mOnePaint,0,90);
            drawArc(canvas,mTwoPaint,90, 90);
            drawArc(canvas,mThreePaint,180,90);
            drawArc(canvas,mFourPaint,270,(float) (360*(mCurrentProgress - 0.75)));
        }
    }


    private void drawArc(Canvas canvas,Paint paint,float start,float end) {
        paint.setStyle(Paint.Style.STROKE);
        float left = getWidth()/2 - mRadius;
        float top = getHeight()/2 -mRadius;
        float right = getWidth()/2 + mRadius;
        float bottom = getHeight()/2 + mRadius;
        RectF rectf = new RectF(left,top,right,bottom);
        canvas.drawArc(rectf,start,end,false,paint);
        canvas.save();
    }

    private void drawBgCircle(Canvas canvas) {
        mBgPaint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(getWidth()/2,getHeight()/2,mRadius,mBgPaint);
    }

    //获取文字 width、height
    private float getTextWidth(String str){
        Rect bounds = new Rect();
        mTextPaint.getTextBounds(str,0,str.length(),bounds);
        return bounds.width();
    }
    private float getTextHeight(String str){
        Rect bounds = new Rect();
        mTextPaint.getTextBounds(str,0,str.length(),bounds);
        return bounds.height();
    }

    //提供外界设置当前进度
    public synchronized void setCurrentProgress(float progress) {
        this.mCurrentProgress = progress;
        invalidate();
    }
}

Here, the more troublesome thing is how to make the arc and the circle overlap each other. There are formulas in the code, which can be understood with the picture below.

 

Step 5: Use outside

package com.wustyq.senseone.app;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.animation.BounceInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.Button;
import android.widget.Toast;

import com.wustyq.senseone.R;
import com.wustyq.senseone.selfView.myProgress;

public class MainActivity extends Activity implements View.OnClickListener {

    private myProgress mp_myProgress;
    private Button bt_test_one;
    private int clickNum = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initWelcome();
        initView();
        initData();
    }

    private void initView() {
        mp_myProgress = findViewById(R.id.mp_myProgress);
        bt_test_one = findViewById(R.id.bt_test_one);
    }

    private void initData() {
        bt_test_one.setOnClickListener(this);
    }

    private void initWelcome() {
        Toast toast = Toast.makeText(this, null, Toast.LENGTH_SHORT);
        toast.setText("欢迎来到第一感知,很高兴为您服务");
        toast.setGravity(Gravity.CENTER,0,0);
        toast.show();
    }

    @Override
    public void onClick(View v) {
        switch(v.getId()){
            case R.id.bt_test_one:
            {
                System.out.println(clickNum + "clickNum");
                if (clickNum == 0){
                    setValueObject(mp_myProgress,0.0f,0.25f);
                    clickNum++;
                }else if (clickNum == 1){
                    setValueObject(mp_myProgress,0.25f,0.5f);
                    clickNum++;
                }else if (clickNum == 2){
                    setValueObject(mp_myProgress,0.5f,0.75f);
                    clickNum++;
                }else if (clickNum == 3){
                    setValueObject(mp_myProgress,0.75f,1.0f);
                    clickNum = 0;
                }
            }
                break;
        }
    }

    private void setValueObject(final myProgress view, float start, float end) {
        ValueAnimator valueAnimator = ObjectAnimator.ofFloat(start, end);
        valueAnimator.setDuration(2000);
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float animatedValue = (float) animation.getAnimatedValue();
                view.setCurrentProgress(animatedValue);
            }
        });
        valueAnimator.start();
    }
}

to sum up

I plan to write a few more components, put them together, and upload the source code together for your reference! ! !

Guess you like

Origin blog.csdn.net/qq_41885673/article/details/114194537