最初にBitmapShaderを知っておく必要があります。
BitmapShaderは、ビットマップを使用して描画されたグラフィックをレンダリングおよび色付けします。実際、画像を使用してグラフィックをマップします。
コンストラクターは次のとおりです。
BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)
最初のパラメータはビットマップオブジェクトです。ビットマップは、描画されたグラフィックをマップするために使用される画像を決定します。
2番目と3番目のパラメーターはすべてShader.TileModeタイプの列挙値であり、CLAMP、REPEAT、MIRRORの3つの値があります。
- CLAMP
CLAMPは、描画されたグラフィックのサイズがビットマップのサイズよりも大きい場合、残りのスペースがビットマップの4つの側面の色で塗りつぶされることを示します。 - REPEAT
REPEATは、描画する図形のサイズがビットマップのサイズよりも大きい場合、描画された領域全体がビットマップで繰り返し並べて表示されることを意味します。
BitmapShaderは、長方形、円、楕円などの単純な形状などのグラフィックの色付けにのみ使用されます。指定されたビットマップを使用して、これらの幾何学的形状内にマップします。
ビットマップのサイズが描画された図のサイズよりも小さい場合、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);
}
}