栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android 自定义View实现圆形加载进度条

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android 自定义View实现圆形加载进度条

效果图

话不多说,咱们直接看代码

首先第一种:

1、创建自定义View类

public class MyRelative extends View {
  
    public MyRelative(Context context) {
        this(context, null); //手动改成this...
    }

    public MyRelative(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);//手动改成this...
    }

    @SuppressLint("ResourceAsColor")
    public MyRelative(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
      
    }
}

2、自定义属性,(在values文件夹下创建一个XML,取名为atts_circle_view.xml)



     //这个name最好和你创建的自定义View类名一样
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    

3、在第三个构造方法中得到自定义属性

  @SuppressLint("ResourceAsColor")
    public MyRelative(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyRelative);
        //圆弧宽度
        mBorderWidth = (int) typedArray.getDimension(R.styleable.MyRelative_border_width, 10);
        //外圆弧颜色
        mOuterColor = typedArray.getColor(R.styleable.MyRelative_outer_color, mOuterColor);
        //内圆弧颜色
        mInnerColor = typedArray.getInteger(R.styleable.MyRelative_inner_color, mInnerColor);
        //字体颜色
        mTextColor = typedArray.getColor(R.styleable.MyRelative_step_text_color, mTextColor);
        //字体大小
        mTextSize = (int) typedArray.getDimensionPixelSize(R.styleable.MyRelative_step_text_size, mTextSize);
        //最大步数
        mMaxStep = typedArray.getInteger(R.styleable.MyRelative_max_step, 10000);
        //当前步数
        mCurrentStep = typedArray.getInteger(R.styleable.MyRelative_curren_step, 8000);
        typedArray.recycle();
}

4、重写onMeasure方法(测量view大小)

 @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);
    }

5、重写onDraw方法(绘制)

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制内圆弧
        int center = getWidth() / 2;
        int r = (getWidth() - mBorderWidth) / 2;
        RectF rectF = new RectF(mBorderWidth / 2, mBorderWidth / 2, center + r, center + r);
        canvas.drawArc(rectF, 135, 270, false, mInnerPaint);
        //绘制外圆弧
        if (mMaxStep == 0) {
            return;
        }
        float radio = (float) mCurrentStep / mMaxStep;
        canvas.drawArc(rectF, 135, 270 * radio, false, mOuterPaint);
        //文字
        String mText = mCurrentStep + "";
        Rect rect = new Rect();
        mTextPaint.getTextBounds(mText, 0, mText.length(), rect);
        int dx = getWidth() / 2 - rect.width() / 2;
        Paint.FontMetricsInt fontMetricsInt = mTextPaint.getFontMetricsInt();
        int dy = fontMetricsInt.bottom - fontMetricsInt.top;
        int baseLine = getHeight() / 2 + dy / 2;
        canvas.drawText(mText, dx, getHeight() / 2 + rect.height() / 2, mTextPaint);
    }

6、要想效果炫酷怎么能少了动画

        写一个方法可以直接在activity中调用

public void setAnimator(int mMaxStep, int mCurrentStep, int duration) {
        this.mMaxStep = mMaxStep;
        ValueAnimator animator = ObjectAnimator.ofFloat(0, mCurrentStep);
        animator.setInterpolator(new DecelerateInterpolator());
        animator.setDuration(duration);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                float value = (float) animator.getAnimatedValue();
                setmCurrentStep((int) value);
            }
        });
        animator.start();
    }

下面附上全部代码

package com.example.customviewdome;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.DecelerateInterpolator;

import androidx.annotation.Nullable;

public class MyRelative extends View {
    //圆弧宽度
    private int mBorderWidth;
    //外圆弧默认颜色
    private int mOuterColor = R.color.salmon;
    //内圆弧默认颜色
    private int mInnerColor = R.color.sandybrown;
    //字体默认颜色
    private int mTextColor = R.color.salmon;
    //字体默认大小
    private int mTextSize = 40;
    //步数
    private int mCurrentStep;
    //创建内圆画笔
    private Paint mInnerPaint;
    //创建外圆画笔
    private Paint mOuterPaint;
    //创建文字画笔
    private Paint mTextPaint;
    //最大步数值
    private int mMaxStep;

    public void setmCurrentStep(int mCurrentStep) {
        this.mCurrentStep = mCurrentStep;
        invalidate();
    }

    public void setmMaxStep(int mMaxStep) {
        this.mMaxStep = mMaxStep;
    }

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

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

    //1、分析需求
    //2、自定义属性
    //3、获得自定义属性
    //4、重写onMeasure
    //5、绘制
    //6、其他(动画等等)
    @SuppressLint("ResourceAsColor")
    public MyRelative(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyRelative);
        //圆弧宽度
        mBorderWidth = (int) typedArray.getDimension(R.styleable.MyRelative_border_width, 10);
        //外圆弧颜色
        mOuterColor = typedArray.getColor(R.styleable.MyRelative_outer_color, mOuterColor);
        //内圆弧颜色
        mInnerColor = typedArray.getInteger(R.styleable.MyRelative_inner_color, mInnerColor);
        //字体颜色
        mTextColor = typedArray.getColor(R.styleable.MyRelative_step_text_color, mTextColor);
        //字体大小
        mTextSize = (int) typedArray.getDimensionPixelSize(R.styleable.MyRelative_step_text_size, mTextSize);
        //最大步数
        mMaxStep = typedArray.getInteger(R.styleable.MyRelative_max_step, 10000);
        //当前步数
        mCurrentStep = typedArray.getInteger(R.styleable.MyRelative_curren_step, 8000);
        typedArray.recycle();
        //创建画笔
        mInnerPaint = new Paint();
        mInnerPaint.setStyle(Paint.Style.STROKE);
        mInnerPaint.setAntiAlias(true);
        mInnerPaint.setColor(mInnerColor);
        mInnerPaint.setStrokeWidth(mBorderWidth);
        mInnerPaint.setStrokeCap(Paint.Cap.ROUND);
        //创建画笔
        mOuterPaint = new Paint();
        mOuterPaint.setStyle(Paint.Style.STROKE);
        mOuterPaint.setAntiAlias(true);
        mOuterPaint.setColor(mOuterColor);
        mOuterPaint.setStrokeWidth(mBorderWidth);
        mOuterPaint.setStrokeCap(Paint.Cap.ROUND);
        //创建文字画笔
        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setColor(mTextColor);
        mTextPaint.setTextSize(mTextSize);
    }

    @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);
        //绘制内圆弧
        int center = getWidth() / 2;
        int r = (getWidth() - mBorderWidth) / 2;
        RectF rectF = new RectF(mBorderWidth / 2, mBorderWidth / 2, center + r, center + r);
        canvas.drawArc(rectF, 135, 270, false, mInnerPaint);
        //绘制外圆弧
        if (mMaxStep == 0) {
            return;
        }
        float radio = (float) mCurrentStep / mMaxStep;
        canvas.drawArc(rectF, 135, 270 * radio, false, mOuterPaint);
        //文字
        String mText = mCurrentStep + "";
        Rect rect = new Rect();
        mTextPaint.getTextBounds(mText, 0, mText.length(), rect);
        int dx = getWidth() / 2 - rect.width() / 2;
        Paint.FontMetricsInt fontMetricsInt = mTextPaint.getFontMetricsInt();
        int dy = fontMetricsInt.bottom - fontMetricsInt.top;
        int baseLine = getHeight() / 2 + dy / 2;
        canvas.drawText(mText, dx, getHeight() / 2 + rect.height() / 2, mTextPaint);
    }

    public void setAnimator(int mMaxStep, int mCurrentStep, int duration) {
        this.mMaxStep = mMaxStep;
        ValueAnimator animator = ObjectAnimator.ofFloat(0, mCurrentStep);
        animator.setInterpolator(new DecelerateInterpolator());
        animator.setDuration(duration);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                float value = (float) animator.getAnimatedValue();
                setmCurrentStep((int) value);
            }
        });
        animator.start();
    }
}

第二种圆形进度条

步骤和以上差不多,下面直接贴出源码

自定义属性



    
        
        
        
        
        
        
        
        
        
        
    

源码 

package com.example.customviewdome;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.DecelerateInterpolator;

import androidx.annotation.Nullable;

public class CircleLoadingView extends View {
    private Context mContext;
    //内圆颜色
    private int mInnerColor;
    //外圆颜色
    private int mOuterColor;
    //圆点颜色
    private int mDotColor;
    //字体颜色
    private int mTextColor;
    //字体大小
    private int mTextSize;
    //创建内圆画笔
    private Paint mInnerPaint;
    //view的宽度
    private int mWidth;
    //view的高度
    private int mHeight;
    //当前进度
    private int mProgress = 0;
    //创建文字画笔
    private Paint mTextPaint;
    //创建小圆圈画笔
    private Paint mDotPaint;
    //小圆圈起点位置
    private int mDotProgress;

    //仿华为圆形加载框
    public CircleLoadingView(Context context) {
        this(context, null);
    }

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

    //1、自定义属性
    //2、测量控件大小
    //3、绘制内圆
    //4、绘制外圆
    @SuppressLint("ResourceAsColor")
    public CircleLoadingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = getContext();
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleLoadingView);
        mInnerColor = typedArray.getColor(R.styleable.CircleLoadingView_in_color, R.color.antiquewhite);
        mOuterColor = typedArray.getColor(R.styleable.CircleLoadingView_out_color, R.color.aqua);
        mTextColor = typedArray.getColor(R.styleable.CircleLoadingView_text_color, R.color.aqua);
        mDotColor = typedArray.getColor(R.styleable.CircleLoadingView_dot_color, R.color.blueviolet);
        mTextSize = typedArray.getDimensionPixelSize(R.styleable.CircleLoadingView_text_size, 20);
        typedArray.recycle();
        //创建画笔
        mInnerPaint = new Paint();
        mInnerPaint.setAntiAlias(true);
        mInnerPaint.setColor(mInnerColor);
        mInnerPaint.setStrokeWidth(DensityUtil.dip2px(mContext, 3));
        mInnerPaint.setStrokeCap(Paint.Cap.ROUND);
        mInnerPaint.setStyle(Paint.Style.STROKE);
        //创建文字画笔
        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setTextSize(mTextSize);
        mTextPaint.setColor(mTextColor);
        mTextPaint.setStyle(Paint.Style.STROKE);
        //创建小圆圈画笔
        mDotPaint = new Paint();
        mDotPaint.setAntiAlias(true);
        mDotPaint.setStrokeWidth(DensityUtil.dip2px(mContext, 10));
        mDotPaint.setStyle(Paint.Style.FILL);
        mDotPaint.setColor(mDotColor);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        //获取宽度
        if (widthMode == MeasureSpec.EXACTLY) {
            //当宽度为精准值或match_parent时直接使用
            mWidth = widthSize;
        } else {
            //当宽度为wrap_content设置控件大小为120dp
            mWidth = DensityUtil.dip2px(mContext, 220);
        }
        //获取高度
        if (heightMode == MeasureSpec.EXACTLY) {
            mHeight = heightSize;
        } else {
            mHeight = DensityUtil.dip2px(mContext, 220);
        }
        setMeasuredDimension(mWidth > mHeight ? mHeight : mWidth, mWidth > mHeight ? mHeight : mWidth);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制圆形
        canvas.save();
        for (int i = 0; i < 100; i++) {
            if (mProgress > i) {
                mInnerPaint.setColor(mInnerColor);
            } else {
                mInnerPaint.setColor(mOuterColor);
            }
            canvas.drawLine(mWidth / 2, 0, mWidth / 2, DensityUtil.dip2px(mContext, 10), mInnerPaint);
            canvas.rotate(3.6f, mWidth / 2, mHeight / 2);
        }
        canvas.restore();
        //绘制文字
        String progreStr = mProgress + "";
        Rect rect = new Rect();
        mTextPaint.getTextBounds(progreStr, 0, progreStr.length(), rect);
        int dx = getWidth() / 2 - rect.width() / 2;
        canvas.drawText(progreStr, dx, getHeight() / 2 + rect.height() / 2, mTextPaint);
        //绘制小圆圈
        canvas.save();
        canvas.rotate(mDotProgress * 3.6f, mWidth / 2, mHeight / 2);
        canvas.drawCircle(mWidth / 2 - (mInnerPaint.getStrokeWidth() * 2), DensityUtil.dip2px(mContext, 10) + DensityUtil.dip2px(mContext, 8), DensityUtil.dip2px(mContext, 3), mDotPaint);
        canvas.restore();
    }

    public void setProgress(int progress) {
        mProgress = progress;
        mDotProgress = progress;
        invalidate();
    }

    public void setAnimation(int progress, int time) {
        ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0, progress);
        valueAnimator.setDuration(time);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                float value = (float) valueAnimator.getAnimatedValue();
                setProgress((int) value);
            }
        });
        valueAnimator.start();
    }

}

在xml文件中引用




    

    


在activity中实例化

package com.example.customviewdome;

import androidx.appcompat.app.AppCompatActivity;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;

public class MainActivity extends AppCompatActivity {

    private MyRelative my_view;
    private CircleLoadingView circleloading;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        circleloading = findViewById(R.id.circleloading);
        circleloading.setAnimation(80, 5000);
        my_view = findViewById(R.id.my_view);
        my_view.setAnimator(100,80,5000);
    }
}

本文中使用到的DensityUtil类是为了将dp转换为px来使用,以便适配不同的屏幕显示效果

public class DensityUtil {
    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
}

以上就是两个效果的源码

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/755498.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号