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,你會發現有三張圓圓的圖片顯示在你的屏幕上呀。

接下來有時間會在這篇文章後面繼續寫圓角圖片的繪製。函數

有問題歡迎你們在評論區討論呀

相關文章
相關標籤/搜索