版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/u011102153/article/details/52367206
一、介绍
- 一个横向进度条
- 下载完成区域有一个滑块不断从左往右滑动(最开始就是被这个吸引的,就想着这个怎么实现的)
- 进度条中间显示当前进度,值得注意的是,进度条文本包含在下载区域中的部分显示为白色
- 点击暂停,进度条颜色改变,进度文本改变
二、分析
根据以上简单介绍,可以抓住要实现的重难点是上面的第2、3点。
1. 进度条文本包含在下载区域中的部分显示为白色怎么实现?
这个和歌词变色的效果是一样的,所以实现原理应该差不多。canvas有一个save的方法,然后设置成CLIP_SAVE_FLAG标志,这个标志的解释是restore the current clip when restore() is called.然后结合canvas的clip方法和restore方法就能实现。后文见代码④。
2. 下载完成区域有一个滑块不断从左往右滑动怎么实现?
首先想到的是画这样一个滑块(其实是一张图片),然后不断根据当前进度修改位置实现移动。需要注意的是这个滑块的移动特点: 滑块的右边界开始进入,最后左边界消失,而且只在下载完成这个区域内有显示(右边界超出下载完成右边界部分不显示)这让我想到两个图层重叠时的显示模式,再看看这幅图,那么这里就可以使用SRC_ATOP模式。
三、实现
1.自定义属性
<declare-styleable name="FlikerProgressBar">
<attr name="textSize" format="dimension|reference"/>
<attr name="loadingColor" format="color|reference"/>
<attr name="stopColor" format="color|reference"/>
</declare-styleable>
private void initAttrs(AttributeSet attrs) {
if (attrs != null) {
TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.FlikerProgressBar);
textSize = (int) ta.getDimension(R.styleable.FlikerProgressBar_textSize, dp2px(12));
loadingColor = ta.getColor(R.styleable.FlikerProgressBar_loadingColor, Color.parseColor("#40c4ff"));
stopColor = ta.getColor(R.styleable.FlikerProgressBar_stopColor, Color.parseColor("#ff9800"));
ta.recycle();
}
}
2.重写onMeasure方法,当height设置为wrap_content时设置为默认高度
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
int height = 0;
switch (heightSpecMode){
case MeasureSpec.AT_MOST:
height = (int) dp2px(DEFAULT_HEIGHT_DP);
break;
case MeasureSpec.EXACTLY:
case MeasureSpec.UNSPECIFIED:
height = heightSpecSize;
break;
}
setMeasuredDimension(widthSpecSize, height);
}
3.重写onDraw方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//1.边框
drawBorder(canvas);
//2.进度
drawProgress();
canvas.drawBitmap(pgBitmap, 0, 0, null);
//3.进度text
drawProgressText(canvas);
//4.变色处理
drawColorProgressText(canvas);
}
①绘制边框
private void drawBorder(Canvas canvas) {
bgPaint.setStyle(Paint.Style.STROKE);
bgPaint.setColor(progressColor);
bgPaint.setStrokeWidth(dp2px(1));
canvas.drawRect(0, 0, getWidth(), getHeight(), bgPaint);
}
②绘制进度
private void drawProgress() {
bgPaint.setStyle(Paint.Style.FILL);
bgPaint.setStrokeWidth(0);
bgPaint.setColor(progressColor);
float right = (progress / MAX_PROGRESS) * getMeasuredWidth();
pgBitmap = Bitmap.createBitmap((int) Math.max(right, 1), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
pgCanvas = new Canvas(pgBitmap);
pgCanvas.drawColor(progressColor);
if(!isStop){
bgPaint.setXfermode(xfermode);
pgCanvas.drawBitmap(flikerBitmap, flickerLeft, 0, bgPaint);
bgPaint.setXfermode(null);
}
}
③绘制进度条显示文本
private void drawProgressText(Canvas canvas) {
textPaint.setColor(progressColor);
progressText = getProgressText();
textPaint.getTextBounds(progressText, 0, progressText.length(), textBouds);
int tWidth = textBouds.width();
int tHeight = textBouds.height();
float xCoordinate = (getMeasuredWidth() - tWidth) / 2;
float yCoordinate = (getMeasuredHeight() + tHeight) / 2;
canvas.drawText(progressText, xCoordinate, yCoordinate, textPaint);
}
④进度条文本变色处理
private void drawColorProgressText(Canvas canvas) {
textPaint.setColor(Color.WHITE);
int tWidth = textBouds.width();
int tHeight = textBouds.height();
float xCoordinate = (getMeasuredWidth() - tWidth) / 2;
float yCoordinate = (getMeasuredHeight() + tHeight) / 2;
float progressWidth = (progress / MAX_PROGRESS) * getMeasuredWidth();
if(progressWidth > xCoordinate){
canvas.save(Canvas.CLIP_SAVE_FLAG);
float right = Math.min(progressWidth, xCoordinate + tWidth);
canvas.clipRect(xCoordinate, 0, right, getMeasuredHeight());
canvas.drawText(progressText, xCoordinate, yCoordinate, textPaint);
canvas.restore();
}
}