常见app欢迎页圆形进度条倒计时功能,可设置显示文字,进度条颜色,宽度,倒计时时间,内圆颜色、设置进度条类型  顺数进度条(0-100)还是倒数进度条(100-0);

先上效果图:

eca996e65d64cf5c340e4ce34773369d.gif

下面介绍实现逻辑:

自定义CircleProgressbar继承TextView,在onDraw()方法里获取view边界,先画一个内部实心圆,然后画一个圆边框,然后接着在圆的中心位置画字(你要显示的字 跳转),然接开始画我们最需要的进度条了。现在画完了,那么如何显示进度条呢,我们通过Runnable 每隔 (倒计时时间秒 / 100)获取进度progress大小,通过invalidate()刷新幕实现圆形倒计时;

附上自定义view代码:public class CircleProgressbar extends TextView {

//外部轮廓的颜色

private int outLineColor = Color.BLACK;

//外部轮廓的宽度

private int outLineWidth = 2;

//内部圆的颜色

private ColorStateList inCircleColors = ColorStateList.valueOf(Color.TRANSPARENT);

//中心圆的颜色

private int circleColor;

//进度条的颜色

private int progressLineColor = Color.BLUE;

//进度条的宽度

private int progressLineWidth = 8;

//画笔

private Paint mPaint = new Paint();

//进度条的矩形区域

private RectF mArcRect = new RectF();

//进度

private int progress = 100;

//进度条类型

private ProgressType mProgressType = ProgressType.COUNT_BACK;

//进度倒计时时间

private long timeMillis = 3000;

//View的显示区域。

final Rect bounds = new Rect();

//进度条通知。

private OnCountdownProgressListener mCountdownProgressListener;

private int listenerWhat = 0;

public CircleProgressbar(Context context) {

this(context, null);

}

public CircleProgressbar(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public CircleProgressbar(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

initialize(context, attrs);

}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)

public CircleProgressbar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {

super(context, attrs, defStyleAttr, defStyleRes);

initialize(context, attrs);

}

private void initialize(Context context, AttributeSet attributeSet) {

mPaint.setAntiAlias(true);

TypedArray typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.CircleProgressbar);

if (typedArray.hasValue(R.styleable.CircleProgressbar_in_circle_color))

inCircleColors = typedArray.getColorStateList(R.styleable.CircleProgressbar_in_circle_color);

else

inCircleColors = ColorStateList.valueOf(Color.TRANSPARENT);

circleColor = inCircleColors.getColorForState(getDrawableState(), Color.TRANSPARENT);

typedArray.recycle();

}

/**

* 设置外部轮廓圆的颜色

*/

public void setOutLineColor(@ColorInt int outLineColor) {

this.outLineColor = outLineColor;

invalidate();

}

/**

* 设置外部轮廓圆的宽度

*/

public void setOutLineWidth(@ColorInt int outLineWidth) {

this.outLineWidth = outLineWidth;

invalidate();

}

/**

* 设置中心圆的颜色

*/

public void setInCircleColor(@ColorInt int inCircleColor) {

this.inCircleColors = ColorStateList.valueOf(inCircleColor);

invalidate();

}

private void validateCircleColor() {

int circleColorTemp = inCircleColors.getColorForState(getDrawableState(), Color.TRANSPARENT);

if (circleColor != circleColorTemp) {

circleColor = circleColorTemp;

invalidate();

}

}

/**

* 设置圆形进度条颜色

*/

public void setProgressColor(@ColorInt int progressLineColor) {

this.progressLineColor = progressLineColor;

invalidate();

}

/**

* 设置圆形进度条宽度

*/

public void setProgressLineWidth(int progressLineWidth) {

this.progressLineWidth = progressLineWidth;

invalidate();

}

/**

* 设置进度条值

*/

public void setProgress(int progress) {

this.progress = validateProgress(progress);

invalidate();

}

private int validateProgress(int progress) {

if (progress > 100)

progress = 100;

else if (progress < 0)

progress = 0;

return progress;

}

/**

* 获取进度值

*/

public int getProgress() {

return progress;

}

/**

* 设置倒计时时间

*/

public void setTimeMillis(long timeMillis) {

this.timeMillis = timeMillis;

invalidate();

}

/**

* 获取倒计时时间

*/

public long getTimeMillis() {

return this.timeMillis;

}

/**

* 设置进度条类型 是0-100 还是100_0

*/

public void setProgressType(ProgressType progressType) {

this.mProgressType = progressType;

resetProgress();

invalidate();

}

private void resetProgress() {

switch (mProgressType) {

case COUNT:

progress = 0;

break;

case COUNT_BACK:

progress = 100;

break;

}

}

/**

* 获取进度条类型

*/

public ProgressType getProgressType() {

return mProgressType;

}

/**

* 设置进度监听

*/

public void setCountdownProgressListener(int what, OnCountdownProgressListener mCountdownProgressListener) {

this.listenerWhat = what;

this.mCountdownProgressListener = mCountdownProgressListener;

}

public void start() {

stop();

post(progressChangeTask);

}

/**

* 开始旋转倒计时

*/

public void reStart() {

resetProgress();

start();

}

public void stop() {

removeCallbacks(progressChangeTask);

}

@Override

protected void onDraw(Canvas canvas) {

//获取view的边界

getDrawingRect(bounds);

int size = bounds.height() > bounds.width() ? bounds.width() : bounds.height();

float outerRadius = size / 2;

//画内部背景

int circleColor = inCircleColors.getColorForState(getDrawableState(), 0);

mPaint.setStyle(Paint.Style.FILL);

mPaint.setColor(circleColor);

canvas.drawCircle(bounds.centerX(), bounds.centerY(), outerRadius - outLineWidth, mPaint);

//画边框圆

mPaint.setStyle(Paint.Style.STROKE);

mPaint.setStrokeWidth(outLineWidth);

mPaint.setColor(outLineColor);

canvas.drawCircle(bounds.centerX(), bounds.centerY(), outerRadius - outLineWidth / 2, mPaint);

//画字

Paint paint = getPaint();

paint.setColor(getCurrentTextColor());

paint.setAntiAlias(true);

paint.setTextAlign(Paint.Align.CENTER);

float textY = bounds.centerY() - (paint.descent() + paint.ascent()) / 2;

canvas.drawText(getText().toString(), bounds.centerX(), textY, paint);

//画进度条

mPaint.setColor(progressLineColor);

mPaint.setStyle(Paint.Style.STROKE);

mPaint.setStrokeWidth(progressLineWidth);

// mPaint.setStrokeCap(Paint.Cap.ROUND);

mPaint.setAntiAlias(true);

int deleteWidth = progressLineWidth + outLineWidth;

mArcRect.set(bounds.left + deleteWidth / 2, bounds.top + deleteWidth / 2, bounds.right - deleteWidth / 2, bounds.bottom - deleteWidth / 2);

canvas.drawArc(mArcRect, -90, -360 * progress / 100, false, mPaint);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int lineWidth = 4 * (outLineWidth + progressLineWidth);

int width = getMeasuredWidth();

int height = getMeasuredHeight();

int size = (width > height ? width : height) + lineWidth;

setMeasuredDimension(size, size);

}

@Override

protected void drawableStateChanged() {

super.drawableStateChanged();

validateCircleColor();

}

private Runnable progressChangeTask = new Runnable() {

@Override

public void run() {

removeCallbacks(this);

switch (mProgressType) {

//判断是顺数进度条还是倒数进度条

case COUNT:

progress += 1;

break;

case COUNT_BACK:

progress -= 1;

break;

}

if (progress >= 0 && progress <= 100) {

if (mCountdownProgressListener != null)

mCountdownProgressListener.onProgress(listenerWhat, progress);

invalidate();

postDelayed(progressChangeTask, timeMillis / 100);

} else

progress = validateProgress(progress);

}

};

public enum ProgressType {

/**

* 顺数进度条,从0-100;

*/

COUNT,

/**

* 倒数进度条,从100-0;

*/

COUNT_BACK;

}

public interface OnCountdownProgressListener {

void onProgress(int what, int progress);

}

}

在java代码中设置你所需要的样式、 时间等;

注意:

在布局文件中需要在自定义布局外包裹一层 LinearLayout ,防止通过Arcrect画最外层的进度条成椭圆问题;

xml布局代码:

android:layout_width="wrap_content"

android:layout_height="wrap_content">

android:id="@+id/tv_red_skip"

android:layout_width="30dp"

android:text="跳过"

android:textColor="#ffffff"

android:textSize="10sp"

android:layout_height="30dp" />

下面附上demo下载地址:

https://download..net/download/shanshan_1117/10299524

点击打开链接

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐