Android自定义View-使用BitmapShader实现圆形图片

前言

在软件开发过程当中自定义View几乎必不可少,今天写下这篇博客记录本身学习自定义View的第一篇---利用BitmapShader作出圆形图片的效果java

先上效果图
android

思路

整个代码主要使用了三个工具:Paint(画笔-用来绘图),BitmapShader(着色器-拉伸图片,画笔的助手),Martix(矩阵-用来缩放图片,着色器的小助手)canvas

总体思路为:
1.重写onMeasure方法获取View宽高的最小值,并将最小值设置为该View的宽与高
2.获取图片资源,并用着色器拉伸放缩图片
3.将着色器配置给画笔,并在画布上将圆形图案画出来
app

代码实现

首先新建一个CircleImageView.java的类,让其继承androidx.appcompat.widget.AppCompatImageView

实现三个构造器方法,咱们主要用到含两个参数的构造方法。

1.定义初始变量

private Paint mPaint;   //建立画笔

    private int mRadius;    //图片的半径大小

    private Matrix mMartix;     //缩放图片的矩阵

    private Bitmap mBitmap;     //Bitmap图片资源

    private BitmapShader mBitmapShader;    //Bitmap着色器,对bitmap进行拉伸

2.重写onMeasure()函数,获取并设置View的宽高

先经过获取图片的最短宽高让图片的宽度与高度保持一致,除以2后即为半径大小

//经过获取图片的最短宽高让图片的宽高保持一致,除以2后即为半径大小
    mRadius = Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2;

而后再从新设置视图的宽高

//从新设置视图的宽高
    setMeasuredDimension(mRadius * 2, mRadius * 2);

onMeasure()部分的完整代码为:

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mRadius = Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2;
        setMeasuredDimension(mRadius * 2, mRadius * 2);
    }

3.进行初始化操做

在第二个构造器中添加init()函数

public CircleImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

新建init()函数,在其中进行初始化操做

第一步先判断是否有图片资源存在,若是没有话就不继续执行后面的方法了

if (getDrawable() == null){
        return;
    }

接下来咱们先对画笔,矩阵进行初始化设置,并将Drawable转化为Bitmap

//实例化画笔
    mPaint = new Paint();

    //实例化矩阵
    mMartix = new Matrix();

    //获取图片资源,并将drawable图片转化为bitmap图片,便于咱们后续的画图
    mBitmap = drawableToBitmap(getDrawable());

这里须要用到private void drawableToBitmap(Drawable drawable);函数,将Drawable转化为Bitmap,由于Bitmap通常用来作空白画布画图

在转换函数中咱们先判断传进来的drawable是否为BitmapDrawable的实例,若是该drawable为BitmapDrawable的实例,就能够直接进行强制转换

if (drawable instanceof BitmapDrawable){
        BitmapDrawable bd = (BitmapDrawable) drawable;
        return bd.getBitmap();
    }

若是不是的话,就能够经过对应的Bitmap画布把drawable内容画到画布中

//取得drawable的宽和高
    int width = drawable.getIntrinsicWidth();
    int height = drawable.getIntrinsicHeight();

    //创建对应的Bitmap
    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

    //创建对应bitmap的画布
    Canvas canvas = new Canvas(bitmap);

    //把drawable内容画到画布中去
    drawable.setBounds(0, 0, width, height);
    drawable.draw(canvas);

     return bitmap;

完整转换代码以下:

private Bitmap drawableToBitmap(Drawable drawable){

        if (drawable instanceof BitmapDrawable){
            BitmapDrawable bd = (BitmapDrawable) drawable;
            return bd.getBitmap();
        }
        else {
            //取得drawable的宽和高
            int width = drawable.getIntrinsicWidth();
            int height = drawable.getIntrinsicHeight();

            //创建对应的Bitmap
            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

            //创建对应bitmap的画布
            Canvas canvas = new Canvas(bitmap);

            //把drawable内容画到画布中去
            drawable.setBounds(0, 0, width, height);
            drawable.draw(canvas);

            return bitmap;
        }
    }

转换为Bitmap后,咱们回到init()函数,继续进行对着色器的初始化

新建Bitmap着色器,传入bitmap对象(避免在onDraw函数中初始化),其中后两个参数为平铺模式

TileMode有三种:
CLAMP 拉伸
REPEAT 重复
MIRROR 镜像ide

//实例化着色器
    mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, 
            Shader.TileMode.CLAMP);

至此,初始化设置完成。

4.重写onDraw()函数,进行绘制

在绘制函数中主要设置矩阵mMartix,着色器mBitmapShader和画笔mPaint三者的属性

首先咱们要为矩阵计算出偏移值,防止因图片的宽高大于View的宽高而形成拉伸效果,即只在圆圈内显示一部分的图像,而不能显示彻底

取bitmap宽高的最小值做为基准,计算缩放比例(必须为浮点数) mRadius*2.0f 是指裁剪后View的宽度,在onMeasure()方法里

//图片的缩放比例
    float mScale = (mRadius * 2.0f) / Math.min(mBitmap.getWidth(), mBitmap.getHeight());

而后设置矩阵偏移度

//设置矩阵的偏移度
    mMartix.setScale(mScale, mScale);

接着咱们让着色器装备上设置好的矩阵,这样就不会出现没法显示完图片的问题啦

//设置着色器的矩阵
    mBitmapShader.setLocalMatrix(mMartix);

最后,把咱们的着色器装配给画笔

//把着色器配给咱们的画笔
    mPaint.setShader(mBitmapShader);

而后就是整个绘制流程的最后一步啦!调用drawCircle函数用画布把圆画出来

//调用drawCircle函数用画布把圆画出来
    canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);

onDraw()函数总体代码以下

@Override
    protected void onDraw(Canvas canvas) {

        //取bitmap宽高的最小值做为基准,计算缩放比例(必须为浮点数)  mRadius*2.0f 是指裁剪后View的宽度,在onMeasure()方法里
        float mScale = (mRadius * 2.0f) / Math.min(mBitmap.getWidth(), mBitmap.getHeight());    //图片的缩放比例

        //接下来使用矩阵防止因view的宽高大于bitmap的宽高而形成拉伸效果
        //设置矩阵的偏移度
        mMartix.setScale(mScale, mScale);

        //设置着色器的矩阵
        mBitmapShader.setLocalMatrix(mMartix);

        //把着色器配给咱们的画笔
        mPaint.setShader(mBitmapShader);

        //调用drawCircle函数用画布把圆画出来
        canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);
    }

至此函数部分已彻底写完,接下来咱们就能够直接去xml文件里使用咱们自定义的View了

<com.aefottt.seventhwork.ui.view.CircleImageView
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="100dp"
        android:layout_margin="15dp"
        android:src="@mipmap/aefottt"/>

    <com.aefottt.seventhwork.ui.view.CircleImageView
        android:layout_width="0dp"
        android:layout_weight="2"
        android:layout_height="100dp"
        android:layout_margin="15dp"
        android:src="@mipmap/aefottt"/>

    <com.aefottt.seventhwork.ui.view.CircleImageView
        android:layout_width="0dp"
        android:layout_weight="3"
        android:layout_height="150dp"
        android:layout_margin="15dp"
        android:src="@mipmap/aefottt"/>

圆形图片的绘制至此结束,而后运行你的app,你会发现有三张圆圆的图片显示在你的屏幕上呀。

接下来有时间会在这篇文章后面继续写圆角图片的绘制。函数

有问题欢迎你们在评论区讨论呀

相关文章
相关标签/搜索