Android圓形圖片不求人,自定義View實現(BitmapShader使用)

在很多APP當中,圓形的圖片是必不可少的元素,美觀大方。本文將帶領讀者去實現一個圓形圖片自定View,力求只用一個Java類來完成這件事情。

一、先上效果圖


二、實現思路

  • 在定義View 的onMeasure()方法裏設置View的寬高相等,應該取寬高中的最小值。
  • 在自定義View的onDraw()裏面使用畫筆paint結合BitmapShaper畫出一個圓形區域。
  • 上述兩步已經可以實現一個圓形圖片,但是如果圖片大於View的設定的寬高,則只會繪製左上角的局域,內容顯示不完全(如下圖)。因此,還應該做好圖片的縮放。

三、具體實現

1.新建一個java類 CircleImageView繼承 ImageView,這個是完整的代碼。

public class CircleImageView extends ImageView {

    private Paint mPaint; //畫筆

    private int mRadius; //圓形圖片的半徑

    private float mScale; //圖片的縮放比例

    public CircleImageView(Context context) {
        super(context);
    }

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

    public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //因爲是圓形圖片,所以應該讓寬高保持一致
        int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
        mRadius = size / 2;

        setMeasuredDimension(size, size);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        mPaint = new Paint();
        Bitmap bitmap = drawableToBitmap(getDrawable());

        //初始化BitmapShader,傳入bitmap對象
        BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

        //計算縮放比例
        mScale = (mRadius * 2.0f) / Math.min(bitmap.getHeight(), bitmap.getWidth());

        Matrix matrix = new Matrix();
        matrix.setScale(mScale, mScale);
        bitmapShader.setLocalMatrix(matrix);


        mPaint.setShader(bitmapShader);

        //畫圓形,指定好中心點座標、半徑、畫筆
        canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);
    }

    //寫一個drawble轉BitMap的方法
    private Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bd = (BitmapDrawable) drawable;
            return bd.getBitmap();
        }
        int w = drawable.getIntrinsicWidth();
        int h = drawable.getIntrinsicHeight();
        Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, w, h);
        drawable.draw(canvas);
        return bitmap;
    }
}

2. onMeasure()方法裏面,計算好寬高

因爲是圓形圖片,所以應該讓寬高保持一致,取測量尺寸寬高中的最小值最爲最終結果。

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //因爲是圓形圖片,所以應該讓寬高保持一致
        int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
        mRadius = size / 2;

        setMeasuredDimension(size, size);
    }

3. onDraw()方法裏面畫出圓形圖片,注意看註釋,很詳細。

@Override
    protected void onDraw(Canvas canvas) {

        mPaint = new Paint();
        Bitmap bitmap = drawableToBitmap(getDrawable());

        //初始化BitmapShader,傳入bitmap對象
        BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

        //計算縮放比例
        mScale = (mRadius * 2.0f) / Math.min(bitmap.getHeight(), bitmap.getWidth());

        Matrix matrix = new Matrix();
        matrix.setScale(mScale, mScale);
        bitmapShader.setLocalMatrix(matrix);


        mPaint.setShader(bitmapShader);

        //畫圓形,指定好中心點座標、半徑、畫筆
        canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);
    }

4. 上一步中的將drwable轉換爲bitmap的方法。

//寫一個drawble轉BitMap的方法
    private Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bd = (BitmapDrawable) drawable;
            return bd.getBitmap();
        }
        int w = drawable.getIntrinsicWidth();
        int h = drawable.getIntrinsicHeight();
        Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, w, h);
        drawable.draw(canvas);
        return bitmap;
    }

四、使用該自定義View

1. 佈局文件裏面使用,此處使用了斯嘉麗的美圖




<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.roundimage.MainActivity"
    >

    <com.roundimage.CircleImageView
        android:id="@+id/image1"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_centerInParent="true"
        android:scaleType="centerCrop"
        android:src="@drawable/beauty"
        />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/image1"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp"
        android:text="斯嘉麗·約翰遜"
        android:textColor="#333333"
        android:textSize="17sp"
        />
</RelativeLayout>

2. 各種效果圖,用於驗證適應性

  • 尺寸都指定爲200dp
   android:layout_width="200dp"
   android:layout_height="200dp"

  • 尺寸都指定爲100dp
   android:layout_width="100dp"
   android:layout_height="100dp"

  • 尺寸都指定不一樣,一個150,一個400
   android:layout_width="100dp"
   android:layout_height="200dp"

  • 尺寸設定爲wrap_content
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"



五、總結

實現圓形圖片有很多種方法:

  • 可以使用一些開源框架如Fresco,這個可以參考本人的另一篇博客 Fresco圖片框架簡介及使用

  • 笨辦法,讓視覺給到一張圓形圖片(如果每張圖都需要處理,可能她會打死你)

  • 笨辦法,用一個view在上面擋住(這個我寫的自己都笑了)

  • 自定義View,就如本文介紹的。

  • 自定義Drawble,這個和自定義view可以相互補充。

總之,如果讀者有需要圓形圖的,可以把這個copy一下自己用,就一個類,簡單精巧。

如果覺得本文對你有幫助,請關注、留言、點讚我,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章