Android开发之路——canvas篇(一)(实现音乐App圆形图片以及圆形进度条风格的View)

先要知道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);
    }

}

效果图

猜你喜欢

转载自blog.csdn.net/z1455841095/article/details/108355714