App中都用版本更新的选项,版本更新页面中都有进度条的UI。今天我们就通过自定义View,实现以下我们自定义的Progress。当然顺便复习以下自定义View。其实原理非常的简单,先上效果图:
进度条的代码如下:
/**
* @author csc
* 2018-12-26
* Todo 数字进度条
*/
public class NumberProgressBar extends View {
private Context mContext;
/**
* 进度
*/
private int progress;
/**
* 小圆的半径
*/
private int smallCircleR;
/**
* 大圆的半径
*/
private int greatCircleR;
/**
* 进度条的高度
*/
private float progressHeight;
/**
* 气泡矩形
*/
private int jR;
/**
* 未完成进度画笔
*/
private Paint paintUncheck;
/**
* 已经完成的进度画笔
*/
private Paint paintCheck;
/**
* 大圆的画笔
*/
private Paint paintGreatCircle;
/**
* 小圆的画笔
*/
private Paint paintSmallCircle;
/**
* 进度文字画笔
*/
private Paint paintText;
/**
* 进度条开始的画笔颜色
*/
private int starColor = 0xffe5e5e5;
public NumberProgressBar(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mContext = context;
paintCheck = new Paint();
paintUncheck = new Paint();
paintGreatCircle = new Paint();
paintSmallCircle = new Paint();
paintText = new Paint();
smallCircleR = dip2px(mContext, 4);
greatCircleR = dip2px(mContext, 8);
progressHeight = dip2px(mContext, 10) / 2;
jR = dip2px(mContext, 6);
initData();
}
/**
* 初始化数据
*/
private void initData() {
//设置未完成进度条的画笔
paintUncheck.setColor(starColor);
paintUncheck.setStrokeWidth(dip2px(mContext, 1));
//抗锯齿
paintUncheck.setDither(true);
//防抖动
paintUncheck.setAntiAlias(true);
paintUncheck.setStyle(Paint.Style.FILL);
//设置已经完成进度条的画笔
paintCheck.setColor(Color.parseColor("#0099FF"));
paintCheck.setStrokeWidth(dip2px(mContext, 1));
paintCheck.setAntiAlias(true);
paintCheck.setDither(true);
paintCheck.setStyle(Paint.Style.FILL);
//大圆画笔
paintGreatCircle.setColor(Color.parseColor("#0099FF"));
paintGreatCircle.setAntiAlias(true);
paintGreatCircle.setStyle(Paint.Style.FILL);
//小圆画笔
paintSmallCircle.setColor(Color.WHITE);
paintSmallCircle.setAntiAlias(true);
paintSmallCircle.setStyle(Paint.Style.FILL);
//设置文字画笔
paintText.setColor(Color.parseColor("#0099FF"));
//设置文字的大小
int paintTextSize = sp2px(mContext, 12);
paintText.setTextSize(paintTextSize);
paintText.setAntiAlias(true);
paintText.setTypeface(Typeface.DEFAULT_BOLD);
}
@SuppressLint("DrawAllocation")
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//得到进度条
float progressFloat = progress / 100.0f;
//获得控件的高度
int viewHeith = getMeasuredHeight();
//jR表示与控件边缘的左右边距,控件的宽度 = 总宽度- 2倍左边距 - 2倍右边距-大圆的半径(为什么要减去大圆,运行就知道了)
int viewWidth = getMeasuredWidth() - 4 * jR-greatCircleR;
//进度条Y的中心坐标 = 控件的高度 - 大圆的半径
int viewCenterY = viewHeith - greatCircleR;
//当前进度的移动距离 = 当前的进度比 + 2倍的左边距
float currentMovedDistance = viewWidth * progressFloat + 2 * jR;
String str = progress + "%";
Rect bounds = new Rect();
paintText.getTextBounds(str, 0, str.length(), bounds);
int textWidth = bounds.width();
int textHeight = bounds.height();
//开始位置为本(文本,距离X的距离,距离Y的位移,画笔对象)
canvas.drawText(str, currentMovedDistance - textWidth / 2, viewHeith - 2 * greatCircleR - jR, paintText);
//未完成进度的圆角矩形
canvas.drawRoundRect(new RectF(currentMovedDistance, viewCenterY - progressHeight, viewWidth + 2 * jR, viewCenterY + progressHeight),
progressHeight, progressHeight, paintUncheck);
//完成进度的圆角矩形
canvas.drawRoundRect(new RectF(2 * jR, viewCenterY - progressHeight, currentMovedDistance, viewCenterY + progressHeight),
progressHeight, progressHeight, paintCheck);
RectF greatOval = new RectF(currentMovedDistance - greatCircleR, viewCenterY - greatCircleR, currentMovedDistance + greatCircleR, viewCenterY + greatCircleR);
RectF smallOval = new RectF(currentMovedDistance - smallCircleR, viewCenterY - smallCircleR, currentMovedDistance + smallCircleR, viewCenterY + smallCircleR);
//大圆
canvas.drawArc(greatOval, 0, 360, true, paintGreatCircle);
//小圆
canvas.drawArc(smallOval, 0, 360, true, paintSmallCircle);
}
/**
* 设置进度
*
* @param progress 传过来的进度
*/
public void setProgress(int progress) {
this.progress = progress;
invalidate();
}
public int dip2px(Context ctx, float dp) {
float density = ctx.getResources().getDisplayMetrics().density;
int px = (int) (dp * density + 0.5f);
return px;
}
public int sp2px(Context context, float spValue) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spValue, context.getResources().getDisplayMetrics());
}
}
使用方法:现在xml中引用
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/update_app_bg"
android:minHeight="190dp"
android:minWidth="260dp">
<com.csc.widget.NumberProgressBar
android:id="@+id/number_progress"
android:layout_width="260dp"
android:layout_height="150dp"/>
</android.support.constraint.ConstraintLayout>
然后再代码中设置:
private int mProgress;
private NumberProgressBar mNumberProgressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNumberProgressBar = findViewById(R.id.number_progress);
updateProgress();
}
private void updateProgress() {
try {
mProgress++;
Message msg = handler.obtainMessage();
msg.what = 100;
msg.obj = mProgress;
handler.sendMessage(msg);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@SuppressLint("HandlerLeak")
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int progress = (int) msg.obj;
mNumberProgressBar.setProgress(progress);
if (progress <100) {
updateProgress();
}
}
};
好啦,这就是我们要实现的效果啦!