The Road to Android Development-Canvas (1) (Implementing a circular picture of a music App and a circular progress bar-style View)

We must first know BitmapShader:

BitmapShader is to use bitmap to render and color the drawn graphics, in fact, it is to use pictures to map the graphics.

The constructor is as follows:

BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)

 

The first parameter is the Bitmap object. The Bitmap determines what picture is used to map the drawn graphics.

The second and third parameters are all enumeration values ​​of type Shader.TileMode, with the following three values: CLAMP, REPEAT and MIRROR.

  • CLAMP
    CLAMP indicates that when the size of the drawn graphics is larger than the size of the Bitmap, the remaining space will be filled with the colors of the four sides of the Bitmap.
  • REPEAT
    REPEAT means that when the size of the figure we draw is larger than the size of the Bitmap, the entire drawn area will be tiled repeatedly with the Bitmap.

BitmapShader is only used to color graphics, such as simple shapes such as rectangles, circles, and ellipses. Use the specified bitmap to map inside these geometric shapes.
When the size of the bitmap is smaller than the size of the drawn figure, the Shader.TileMode determines how to (fill) the map.

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);
    }

}

Effect picture

 

Guess you like

Origin blog.csdn.net/z1455841095/article/details/108355714