还在为了一个小小的效果,依赖一个一个的第三方?
看着别人随随便便写了一个自定义效果,自己却除了666啥也做不了?
如果你认为自己就是这样,那么,你要好好看一下这篇文章了!
进度条作为移动开发的一个常用功能,相信你一定不陌生。本篇,我们要手动编写一个简单的进度条,模拟一下下载的效果。
一、效果
二、分析
自定义View,分析里面的元素:
1、进度条背景颜色
2、进度条背景是否是实心
3、进度条的颜色
4、进度(文字)的颜色和字体大小
5、进度条的圆角大小
三、实现
1、自定义View类,继承View
public class CustomProgressView extends View {
public CustomProgressView(Context context) {
this(context, null);
}
public CustomProgressView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
2、在attr文件中,定义样式
定义元素,并赋予正确的属性类型。
3、在构造方法中,调用obtainStyledAttributes方法,获取自定义的style,并初始化个属性,同时,初始化画笔Paint
private int cp_percent_textsize = 18;//百分比字体大小
private int cp_percent_textcolor = 0xff009ACD;
private int cp_background_color = 0xff636363;
private int cp_progress_color = 0xff00C5CD;
private boolean cp_background_is_stroke = true;
private int cp_rect_round = 5;
private Paint mPaint;
private int mCenterX;
private int mCenterY;
private int progressCurrent = 0;
private int progressMax = 100;
public CustomProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.obtainStyledAttributes(R.styleable.CustomProgressView);
cp_percent_textsize = (int) typedArray.getDimension(R.styleable.CustomProgressView_cp_percent_textsize, cp_percent_textsize);
cp_percent_textcolor = typedArray.getColor(R.styleable.CustomProgressView_cp_percent_textcolor, cp_percent_textcolor);
cp_background_color = typedArray.getColor(R.styleable.CustomProgressView_cp_background_color, cp_background_color);
cp_progress_color = typedArray.getColor(R.styleable.CustomProgressView_cp_progress_color, cp_progress_color);
cp_background_is_stroke = typedArray.getBoolean(R.styleable.CustomProgressView_cp_background_is_stroke, cp_background_is_stroke);
cp_rect_round = (int) typedArray.getDimension(R.styleable.CustomProgressView_cp_rect_round, cp_rect_round);
typedArray.recycle();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
4、复写最重要的方法onDraw
@Override
protected void onDraw(Canvas canvas) {
mCenterX = getWidth() / 2;
mCenterY = getHeight() / 2;
drawHorProgress(mPaint, canvas);
}
private void drawHorProgress(Paint paint, Canvas canvas) {
//画背景
paint.setColor(cp_background_color);
if (cp_background_is_stroke) {
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(1);
} else {
paint.setStyle(Paint.Style.FILL);
}
canvas.drawRoundRect(new RectF(mCenterX - getWidth() / 2, mCenterY - getHeight() / 2,
mCenterX + getWidth() / 2, mCenterY + getHeight() / 2), cp_rect_round, cp_rect_round, paint);
//画进度条
paint.setColor(cp_progress_color);
paint.setStyle(Paint.Style.FILL);
canvas.drawRoundRect(new RectF(mCenterX - getWidth() / 2, mCenterY - getHeight() / 2,
(int) (progressCurrent * getWidth() / progressMax), mCenterY + getHeight() / 2), cp_rect_round, cp_rect_round, paint);
//画文字
paint.setColor(cp_percent_textcolor);
paint.setTextSize(cp_percent_textsize);
paint.setStyle(Paint.Style.FILL);
String value_str = (int) (progressCurrent * 100 / progressMax) + "%";
Rect rect = new Rect();
paint.getTextBounds(value_str, 0, value_str.length(), rect);
float textWidth = rect.width();
float textHeight = rect.height();
if (textWidth >= getWidth()) {
textWidth = getWidth();
}
Paint.FontMetrics metrics = paint.getFontMetrics();
float baseline = (getMeasuredHeight() - metrics.bottom + metrics.top) / 2 - metrics.top;
canvas.drawText(value_str, mCenterX - textWidth / 2, baseline, paint);
}
步骤:
1、想一下,其实很简单。
进度条背景和进度条,就是两个圆角矩形叠加在一起。最后再把文字画在矩形的中间位置。
2、找到View的中心点,getWidth / 2 , getHeight / 2。
3、画背景。
其实背景很简单。固定的圆角矩形。left、top、right、bottom坐标其实是固定的。根据中心点,很容易画出来。
4、画进度条。
进度条是根据的进度值的变化实时刷新的。所以我们要定义一个当前进度progressCurrent和最大进度progressMax。
为什么要定义最大进度?实际生产中,你要根据下载文件的总大小和当前已经下载的大小来计算进度,所以这个是要设置的。
仔细分析,可以知道,在你画进度条的时候,其实只有一个坐标值是变化的,那就是 right 。你可以根据当前进度的百分比来计算当前精度下的 right 占宽度的多少比例。
5、画文字
使文字居中的baseline是一个知识点,需要重点掌握。
6、给各属性值设置setter和getter方法。
这里主要说一下,进度值的设定。
public int getProgressCurrent() {
return progressCurrent;
}
public void setProgressCurrent(int progressCurrent) {
if (progressCurrent > progressMax) {
this.progressCurrent = progressMax;
} else {
this.progressCurrent = progressCurrent;
}
postInvalidate();
}
当当前进度超过最大进度时,当前进度设定为最大进度。(当前进度为100%的下一秒,就会出现超过最大进度的情况)
记得重新绘制View 调用postInvalidate();方法。
5、布局
6、跑起来
mCustomProgressView = view.findViewById(R.id.cpv_one);
mCustomProgressView.setProgressMax(100);
mCustomProgressView.setCp_background_color(Color.parseColor("#A2CD5A"));
mCustomProgressView.setCp_percent_textcolor(Color.RED);
mCustomProgressView.setCp_rect_round(16);
mCustomProgressView.setCp_background_is_stroke(false);
mCustomProgressView.setCp_percent_textsize(30);
view.findViewById(R.id.bt_start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (progressCurrent != 0) {
progressCurrent = 0;
return;
}
mRunnable = new Runnable() {
@Override
public void run() {
progressCurrent += 1;
mCustomProgressView.setProgressCurrent(progressCurrent);
mHandler.postDelayed(mRunnable, 5);
}
};
mHandler.postDelayed(mRunnable, 1);
}
});
OVER ! ! !
扫码关注,共同进步