先要知道BitmapShader:
BitmapShader 就是用bitmap对绘制的图形进行渲染着色,其实就是用图片对图形进行贴图.
构造函数如下:
BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)
第一个参数是Bitmap对象,该Bitmap决定了用什么图片对绘制的图形进行贴图。
第二个参数和第三个参数都是Shader.TileMode类型的枚举值,有以下三个取值:CLAMP 、REPEAT 和 MIRROR。
- CLAMP
CLAMP表示,当所画图形的尺寸大于Bitmap的尺寸的时候,会用Bitmap四边的颜色填充剩余空间。 - REPEAT
REPEAT表示,当我们绘制的图形尺寸大于Bitmap尺寸时,会用Bitmap重复平铺整个绘制的区域。
BitmapShader仅用于对图形着色,如矩形、圆形、椭圆等简单形状。在这些几何形状内部用指定的bitmap进行贴图.
当bitmap的尺寸小于绘制的图形尺寸时,由Shader.TileMode决定了如何进行(填充)贴图
public class CircleProgressImageView extends androidx.appcompat.widget.AppCompatImageView {
private Paint mCirclePaint; //圆画笔
private Paint mArcPaint; //圆弧画笔
private Paint mImgPaint; //图片bitmap画笔
private int mHeight; //view的宽度
private int mWidth; //view高度
private float strokeWidth = 5.0f; //圆与圆弧画笔线条宽度
private float progress = 0.0f; //进度条
private float progressDoge = 0.0f; //图片bitmap旋转角度
private float maxDrage = 360.0f;//圆弧的结尾角度360度
private Handler handler = new Handler(Looper.myLooper()); //android11之后 无参构造的Handler已经被废弃,官方建议使用此构造方法
private Handler handler2 = new Handler(Looper.myLooper());
MyRun myRun = new MyRun(); //进度定时器
My2Run my2Run = new My2Run(); //图片旋转定时器
private boolean isFlag = false;
private Matrix matrix; //图片旋转以及比例缩放用到的3*3矩阵
ProgressListener progressListener; //进度监听器
public CircleProgressImageView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
initPaint();
matrix = new Matrix(); //矩阵
}
//初始化画笔
private void initPaint(){
mCirclePaint = new Paint();
mCirclePaint.setColor(Color.parseColor("#ffffff"));
mCirclePaint.setStyle(Paint.Style.STROKE);
mCirclePaint.setStrokeWidth(strokeWidth);
mCirclePaint.setAntiAlias(true);
mArcPaint = new Paint();
mArcPaint.setAntiAlias(true);
mArcPaint.setStrokeCap(Paint.Cap.ROUND);
mArcPaint.setColor(Color.parseColor("#FF6F6D"));
mArcPaint.setStyle(Paint.Style.STROKE);
mArcPaint.setStrokeWidth(strokeWidth);
mImgPaint = new Paint();
mImgPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mImgPaint.setAntiAlias(true); //抗锯齿
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
handler.postDelayed(myRun,500);
handler2.postDelayed(my2Run,10);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mHeight = getHeight();
mWidth = getWidth();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float cx = mWidth / 2; //canva画出的圆心坐标(cx,cy)
float cy = mHeight / 2;
float radius = mWidth / 2 - strokeWidth / 2;//圆以及圆弧度半径
canvas.drawCircle(cx,cy,radius,mCirclePaint); //先绘制背景圆环
float margin = strokeWidth / 2;
RectF rectF = new RectF(margin,margin,mWidth - margin,mHeight - margin);
mImgPaint.setShader(getBitmapShader(BitmapFactory.decodeResource(getResources(),R.mipmap.avatar))); //拿到Shader纹理
canvas.drawCircle(cx, cy, mWidth / 2 - strokeWidth, mImgPaint); //绘制圆形图片
canvas.drawArc(rectF,-90,progress,false,mArcPaint); //绘制进度圆弧
if(progressListener != null) {
progressListener.getProgress(progress / maxDrage);
}
}
//主要圆形个图片方法
private BitmapShader getBitmapShader(Bitmap bitmap) {
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); //CLAMP拉伸
float scale = Math.max(mWidth * 1.0f / bitmap.getWidth(), mHeight * 1.0f / bitmap.getHeight()); //以最小宽度为缩放比例
matrix.setScale(scale, scale); //利用矩阵对图片进行按比例缩放
matrix.postRotate(progressDoge,mWidth / 2,mWidth / 2); //圆形图片旋转
bitmapShader.setLocalMatrix(matrix);
return bitmapShader;
}
class MyRun implements Runnable {
@Override
public void run() {
progress++;
if(progress <= maxDrage) {
invalidate();
handler.postDelayed(myRun,10);
}
}
}
class My2Run implements Runnable {
@Override
public void run() {
progressDoge+=0.5f;
invalidate();
handler2.postDelayed(my2Run,10);
}
}
public void setProgressListener(ProgressListener progressListener) {
this.progressListener = progressListener;
}
public interface ProgressListener {
void getProgress(float progress);
}
}