Android自定义圆形进度条

Android自定义圆形进度条

github地址:https://github.com/opq1289/CircleProgressView

效果图:
无动画:

有动画:

整圆:

切割圆:

具体步骤:

1. 绘制最基础的两个圆

定义两个画笔:

//进度条画笔
mProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mProgressPaint.setStyle(Paint.Style.STROKE);
mProgressPaint.setStrokeWidth(30);
mProgressPaint.setColor(Color.parseColor("#d81b60"));
//背景圆画笔
mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBackgroundPaint.setStyle(Paint.Style.STROKE);
mBackgroundPaint.setStrokeWidth(30);
mBackgroundPaint.setColor(Color.parseColor("#f1f1f1"));
复制代码

画圆:

mRectf = new RectF(0, 0, 200, 200);
canvas.drawCircle(100, 100, 100, mBackgroundPaint);
canvas.drawArc(mRectf, 0, 120, false, mProgressPaint);
复制代码

边缘被切割,增加参数进度条宽度,优化边缘:

private void initPaint() {
    //进度条画笔
    mProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mProgressPaint.setStyle(Paint.Style.STROKE);
    mProgressPaint.setStrokeWidth(mProgressWidth);
    mProgressPaint.setColor(Color.parseColor("#d81b60"));
    //背景圆画笔
    mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mBackgroundPaint.setStyle(Paint.Style.STROKE);
    mBackgroundPaint.setStrokeWidth(mProgressWidth);
    mBackgroundPaint.setColor(Color.parseColor("#f1f1f1"));
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    mRectf = new RectF(mProgressWidth / 2, mProgressWidth / 2, 200 - mProgressWidth / 2, 200 - mProgressWidth / 2);
    canvas.drawCircle(100, 100, 100 - mProgressWidth / 2, mBackgroundPaint);
    canvas.drawArc(mRectf, 0, 120, false, mProgressPaint);
}
复制代码

2. 计算尺寸

main_activity.xml中的布局是:

android:layout_width="100dp"
android:layout_height="100dp"
复制代码

显示布局边界后发现view的宽高是屏幕宽高:

重新设置view的尺寸:

//设置默认最小尺寸
private int mDefaultWidth = CommonUtil.dp2px(getContext(), 10);
复制代码
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = measureWidth(widthMeasureSpec);
    int height = measureHeight(heightMeasureSpec);
    mViewWidth = Math.min(width, height);
    setMeasuredDimension(mViewWidth, mViewWidth);
}
复制代码
private int measureWidth(int widthMeasureSpec) {
    int width;
    int size = MeasureSpec.getSize(widthMeasureSpec);
    int mode = MeasureSpec.getMode(widthMeasureSpec);
    switch (mode) {
        case MeasureSpec.EXACTLY:
            width = size < mProgressWidth ? mProgressWidth : size;
            break;
        case MeasureSpec.AT_MOST:
            width = mDefaultWidth * 2;
            break;
        default:
            width = CommonUtil.getScreenWidthInPx(getContext());
            break;
    }
    return width;
}

private int measureHeight(int heightMeasureSpec) {
    int height;
    int size = MeasureSpec.getSize(heightMeasureSpec);
    int mode = MeasureSpec.getMode(heightMeasureSpec);
    switch (mode) {
        case MeasureSpec.EXACTLY:
            height = size < mProgressWidth ? mProgressWidth : size;
            break;
        case MeasureSpec.AT_MOST:
            height = mDefaultWidth * 2;
            break;
        default:
            height = CommonUtil.getScreenHeightInPx(getContext());
            break;
    }
    return height;
}
复制代码

然后修改绘制:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    mRectf = new RectF(mProgressWidth / 2, mProgressWidth / 2, mViewWidth - mProgressWidth / 2, mViewWidth - mProgressWidth / 2);
    canvas.drawCircle(mViewWidth / 2, mViewWidth / 2, mViewWidth / 2 - mProgressWidth / 2, mBackgroundPaint);
    canvas.drawArc(mRectf, 0, 120, false, mProgressPaint);
}
复制代码

至此,静态进度条就画好了。

将参数设置为动态,通过方法和属性设置。

<declare-styleable name="CircleProgressView">
    <attr name="progressWidth" format="dimension"/>
    <attr name="progressColor" format="reference"/>
    <attr name="backgroundColor" format="reference"/>
    <attr name="startAngle" format="integer"/>
</declare-styleable>

复制代码
public CircleProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    initPaint();
    TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.CircleProgressView, defStyleAttr, 0);
    mProgressWidth = (int) typedArray.getDimension(R.styleable.CircleProgressView_progressWidth, mDefaultWidth);
    mProgressColor = (int) typedArray.getDimension(R.styleable.CircleProgressView_progressColor, ContextCompat.getColor(getContext(), R.color.colorAccent));
    mStartAngle = typedArray.getInt(R.styleable.CircleProgressView_startAngle, 0);
    mEndAngle = typedArray.getInt(R.styleable.CircleProgressView_startAngle, 360);
    mBackgroundColor = (int) typedArray.getDimension(R.styleable.CircleProgressView_backgroundColor, ContextCompat.getColor(getContext(), R.color.grey_f1));
    typedArray.recycle();

    mProgressPaint.setStrokeWidth(mProgressWidth);
    mProgressPaint.setColor(mProgressColor);

    mBackgroundPaint.setStrokeWidth(mProgressWidth);
    mBackgroundPaint.setColor(mBackgroundColor);
}

复制代码
3. 添加动画
public void setProgress(float progress) {
    mValueAnimator = ValueAnimator.ofFloat(progress);
    mValueAnimator.setDuration(1000);
    mValueAnimator.setInterpolator(new LinearInterpolator());
    mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mProgress = (float) animation.getAnimatedValue();
            invalidate();
        }
    });
    mValueAnimator.start();
}

复制代码

增加进度监听:

public interface OnProgressChangedListener {
    void onProgressChanged(float currentProgress);
}

复制代码
public void setOnProgressChangedListener(OnProgressChangedListener listener) {
    mListener = listener;
}

复制代码

在布局中增加文字,设置居中:

4. 优化代码

增加静态和动画的区分:

/**
* @param progress      进度
* @param showAnimation 是否展示动画
*/
public void setProgress(float progress, boolean showAnimation) {
    mShowAnimation = showAnimation;
    if (mValueAnimator != null && mValueAnimator.isRunning()) {
        mValueAnimator.cancel();
    }
    if (mShowAnimation) {
        mValueAnimator = ValueAnimator.ofFloat(progress);
        mValueAnimator.setDuration(mDuration);
        mValueAnimator.setInterpolator(new LinearInterpolator());
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mProgress = (float) animation.getAnimatedValue();
                if (mListener != null) {
                    mListener.onProgressChanged(mProgress);
                }
                invalidate();
            }
        });
        mValueAnimator.start();
    } else {
        mProgress = progress;
        invalidate();
    }
}

复制代码

设置画笔类型,增加圆头画笔:

public void setCap(Paint.Cap cap) {
    mProgressPaint.setStrokeCap(cap);
    mBackgroundPaint.setStrokeCap(cap);
}

复制代码

5. 增加切割圆类型

增加进度条类型mProgressType:

/**
 * 整圆进度条
 */
public static final int TYPE_CIRCLE = 0;
/**
 * 切割圆进度条
 */
public static final int TYPE_CLIP = 1;

复制代码

切割圆从开始角度到结束角度之间,总进度为100。所以这种情况下:总进度=终止角度 - 起始角度

设置进度的方法修改:

public void setProgress(float progress, boolean showAnimation) {
    mShowAnimation = showAnimation;
    if (mProgressType == TYPE_CLIP) {
        progress = (int) ((mEndAngle - mStartAngle) * 100 / 360.0f);
        mTotalProgress = progress;
    } else {
        mTotalProgress = 100;
    }
    if (mValueAnimator != null && mValueAnimator.isRunning()) {
        mValueAnimator.cancel();
    }
    if (mShowAnimation) {
        mValueAnimator = ValueAnimator.ofFloat(progress);
        mValueAnimator.setDuration(mDuration);
        mValueAnimator.setInterpolator(new LinearInterpolator());
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mProgress = (float) animation.getAnimatedValue();
                if (mListener != null) {
                    mListener.onProgressChanged(mProgress * 100 / mTotalProgress);
                }
                invalidate();
            }
        });
        mValueAnimator.start();
    } else {
        mProgress = progress;
        invalidate();
    }
}

复制代码

OnDraw修改,区分切割圆和整圆:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    mRectf = new RectF(mProgressWidth / 2, mProgressWidth / 2, mViewWidth - mProgressWidth / 2, mViewWidth - mProgressWidth / 2);
    if (mProgressType == TYPE_CIRCLE) {
        canvas.drawCircle(mViewWidth / 2, mViewWidth / 2, mViewWidth / 2 - mProgressWidth / 2, mBackgroundPaint);
        canvas.drawArc(mRectf, mStartAngle, mProgress * 360 / 100, false, mProgressPaint);
    } else if (mProgressType == TYPE_CLIP) {
        canvas.drawArc(mRectf, mStartAngle, mEndAngle - mStartAngle, false, mBackgroundPaint);
        canvas.drawArc(mRectf, mStartAngle, mProgress * 360 / 100, false, mProgressPaint);
    }
}

复制代码

完成。

github地址:https://github.com/opq1289/CircleProgressView

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要在Android自定义圆形进度条,可以按照以下步骤进行: 1. 首先,在XML布局文件中添加一个半圆形的View。可以使用自定义的View继承自View类,或者使用现有的绘图类如Canvas和Path来绘制半圆形。 2. 在自定义的View中,重写onDraw方法,通过Canvas对象绘制半圆形。可以使用drawArc方法来画出一个弧线,指定起点、终点和角度,来绘制半圆形。 3. 在自定义的View中添加一个属性来表示当前进度。可以使用属性动画或者定时器来不断更新进度,并调用invalidate方法来重绘View。 4. 在自定义的View中添加一些自定义属性,如颜色、宽度等,来实现进度条的样式定制。 5. 在Activity中使用这个自定义的View,可以通过findViewById找到它,并设置进度条的属性和监听器等。 通过以上步骤,就可以实现一个自定义的半圆形进度条。根据具体需求和设计,可以进行更多的样式和功能定制,如添加文本显示、动画效果等。 ### 回答2: 要实现Android自定义圆形进度条,可以采用以下步骤: 1. 首先,在布局文件中创建一个自定义View,用于绘制半圆形进度条。可以使用Canvas来进行绘制。在View的构造函数中初始化一些必要的参数,如进度条的颜色、背景颜色等。 2. 在自定义View的onDraw()方法中,使用Canvas绘制一个半圆形的背景,可以使用drawArc()方法,并设置起始角度和扫描角度。 3. 接着,绘制进度条的一段弧线。根据进度的值计算出起始和结束的角度,并使用drawArc()方法进行绘制。 4. 在Activity中,实例化自定义View,并将其添加到布局中。可以使用setProgress()方法来设置进度条的进度值。 5. 如果需要实现动画效果,可以使用ValueAnimator来改变进度值,并在动画过程中不断调用invalidate()方法来刷新视图。 总结:自定义圆形进度条的关键是使用Canvas的drawArc()方法进行绘制,根据进度值来计算起始和结束的角度,并使用invalidate()方法来进行视图的刷新。通过这些步骤,即可实现Android自定义圆形进度条的效果。 ### 回答3: 要实现Android自定义圆形进度条,可以通过自定义View来实现。 首先,创建一个继承自View的自定义View类,并重写其中的三个方法:onMeasure()、onDraw()和onSizeChanged()。 在onMeasure()方法中,设置View的宽度和高度,可以根据需求来设置,比如设置为200dp,然后将测量的结果保存。 在onSizeChanged()方法中,获取View的宽度和高度,用于后续计算绘制进度条的位置。 在onDraw()方法中,绘制半圆形进度条的背景和进度。首先,使用Paint类创建两个画笔,一个用于绘制背景,一个用于绘制进度。然后,通过Path类创建一个半圆形的路径,使用drawPath()方法绘制出半圆形。接着,根据进度计算出进度条的结束位置,使用drawArc()方法绘制出进度条。最后,使用drawText()方法绘制出进度的文字。 在Activity或Fragment中使用自定义View,可以通过布局文件或代码的方式进行添加。如果使用布局文件,可以在XML文件中使用自定义的命名空间,并设置View的属性。如果使用代码,可以在onCreate()方法中使用addView()方法添加。 以上就是实现Android自定义圆形进度条的大致步骤。根据具体需求,还可以添加其他功能,比如添加动画效果,改变进度条的颜色等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值