ImageView 繪製圓角效果_BitmapShader

前言

之前我們已經提到過,我們可以使用兩種方式來實現圓角圖片的效果。一種是使用Xfermode,另一種是BitmapShader來實現。下面我將介紹BitmapShader用法。

使用BitmapShader的方式實現

1.自定義屬性在attrs.xml文件中

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <attr name="borderRadius" format="dimension" />

    <attr name="type">
        <enum name="circle" value="0"/>
        <enum name="round" value="1"/>
    </attr>
    <declare-styleable name="RoundImageView">
        <attr name="borderRadius"/>
        <attr name="type"/>
    </declare-styleable>

</resources>

2.自定義ImageView

public class RoundImageView extends ImageView {

    private int type;
    private static final int TYPE_CIRCLE = 0;
    private static final int TYPE_ROUND = 1;

    //圓形半徑大小
    private int mRadius;

    //圓角矩形半徑大小
    private int mBorderRadius;
    //圓角默認值
    private static final int BODER_RADIUS_DEFAULT = 10;

    private Paint mPaint;

    //矩陣用來縮放
    private Matrix mMatrix;

    private BitmapShader mBitmapShader;

    private RectF mRectF;

    public RoundImageView(Context context, AttributeSet attrs) {
        super(context, attrs);

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mMatrix = new Matrix();

        //獲取自定義的屬性
        TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.RoundImageView);
        int defvalue = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,BODER_RADIUS_DEFAULT,getResources().getDisplayMetrics());
        mBorderRadius = a.getDimensionPixelSize(R.styleable.RoundImageView_borderRadius,defvalue);
        type = a.getInt(R.styleable.RoundImageView_type,TYPE_CIRCLE);
        a.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        //爲圓形圖片,所以應該讓寬高保持一致,獲得半徑大小
        if (type == TYPE_CIRCLE){
            int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
            mRadius = size / 2;
            setMeasuredDimension(size, size);
        }

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mRectF = new RectF(0,0,getWidth(),getHeight());
    }

    @Override
    protected void onDraw(Canvas canvas) {

        if (getDrawable() == null){
            return;
        }
        setUpShader();
        if (type == TYPE_ROUND){
            canvas.drawRoundRect(mRectF,mBorderRadius,mBorderRadius,mPaint);
        }else {
            canvas.drawCircle(mRadius,mRadius,mRadius,mPaint);
        }

    }

    private void setUpShader() {
        Drawable drawable = getDrawable();
        if (drawable == null){
            return;
        }
        Bitmap bitmap = drawableToBitmap(drawable);

        //初始化BitmapShader,傳入bitmap對象,在指定區域內繪製bitmap
        mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

        //計算縮放比例
        float scale = 1.0f;
        if (type == TYPE_CIRCLE){
            //根據最小寬高,設置比例
            int size = Math.min(bitmap.getWidth(),bitmap.getHeight());
            scale = mRadius * 2.0f/ size;
        }else if (type == TYPE_ROUND){
            // 如果圖片的寬或者高與view的寬高不匹配,計算出需要縮放的比例;
            // 縮放後的圖片的寬高,一定要大於我們view的寬高;所以我們這裏取大值
            scale = Math.max(getMeasuredWidth() * 1.0f / bitmap.getWidth(), getMeasuredHeight() * 1.0f / bitmap.getHeight());
        }
        //shader的變換矩陣,用於放大或者縮小
        mMatrix.setScale(scale,scale);
        mBitmapShader.setLocalMatrix(mMatrix);

        mPaint.setShader(mBitmapShader);
    }

    /**
     * 將drawable 轉化爲 Bitmap
     * @param drawable
     * @return
     */
    private Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable instanceof BitmapDrawable){
            BitmapDrawable bitmapDrawable = (BitmapDrawable)drawable;
            return bitmapDrawable.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;
    }

}

3.佈局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:roundview="http://schemas.android.com/apk/res-auto"
              xmlns:tools="http://schemas.android.com/tools"
              android:id="@+id/activity_main"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
              android:padding="10dp">


    <mo.yumf.com.myviews.RoundImageView
        android:id="@+id/Roundview"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_marginTop="20dp"
        roundview:borderRadius="5dp"
        roundview:type="round"/>

    <mo.yumf.com.myviews.RoundImageView
        android:id="@+id/Circleview"
        android:layout_width="200dp"
        android:layout_height="100dp"
        roundview:type="circle"
        android:layout_marginTop="20dp"/>

</LinearLayout>

關於BitmapShader類
BitmapShader是Shader的子類,可以通過Paint.setShader(Shader shader)來設置。構造方法:
BitmapShader mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

TileMode的取值有三種:
CLAMP :拉伸,這個拉伸的是圖片最後的那一個像素;橫向的最後一個橫行像素,不斷的重複,縱項的那一列像素,不斷的重複;
REPEAT: 重複,就是橫向、縱向不斷重複這個bitmap;
MIRROR :鏡像,橫向不斷翻轉重複,縱向不斷翻轉重複;

BitmapShader通過設置給mPaint,然後用這個mPaint繪圖時,就會根據你設置的TileMode,對繪製區域進行着色。
這裏需要注意一點:就是BitmapShader是從你的畫布的左上角開始繪製的,不在view的右下角繪製個正方形,它不會在你正方形的左上角開始。

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