1. 程式人生 > >Android 自定義View實現圓形切圖的效果

Android 自定義View實現圓形切圖的效果

使用自定義View實現圓形ImageView的效果
這裡寫圖片描述

目前圓形邊框還需要調整,這裡有點問題

實現思路

使用一個Paint,將得到的Bitmap設定成paint的Shader,設定完成後,使用Matrix調整圖片至居中,使用RectF約束邊框,最後完成繪製

初始化Paint,設定Shader


    private void init() {
        getBitmapFromDrawable();
        if (mBitmap == null) {
            return;
        }
        mShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

        // bitmap paint
mFillPaint = new Paint(); mFillPaint.setAntiAlias(true); mFillPaint.setStyle(Paint.Style.FILL); mFillPaint.setShader(mShader); // border paint mBoundPaint = new Paint(); mBoundPaint.setAntiAlias(true); mBoundPaint.setStyle(Paint.Style.STROKE); mBoundPaint.setStrokeWidth(mBorderWidth); mBoundPaint.setColor(mBorderColor); // border rectF
mBorderBound.set(calculateBitmapBound()); // bitmap rectF mBitmapBound.set(calculateBitmapBound()); mBitmapBound.inset(mBorderWidth - 10, mBorderWidth - 10); updateShaderMatrix(); }

獲取Drawable


    private Bitmap getBitmapFromDrawable() {
        Drawable drawable = getDrawable();
        if
(drawable instanceof BitmapDrawable) { mBitmap = ((BitmapDrawable) drawable).getBitmap(); mBitmapWidth = mBitmap.getWidth(); mBitmapHeight = mBitmap.getHeight(); return mBitmap; } return null; }

計算邊距


    /**
     * 計算Bitmap邊距
     */
    private RectF calculateBitmapBound() {
        int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
        int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();
        int sideLength = Math.min(availableWidth, availableHeight); // 可用的直徑
        mRadius = sideLength / 2;

        int left = getPaddingLeft() + (availableWidth - sideLength) / 2;
        int top = getPaddingTop() + (availableHeight - sideLength) / 2;

        Log.d(TAG, "calculateBitmapBound: left >>> " + left + " top >>> " + top + " right >>> "
                + (left + sideLength) + " right >>> " + top + " bottom >>> " + (top + sideLength));
        return new RectF(left, top, left + sideLength, top + sideLength);
    }

調整Matrix,防止只顯示圖片邊角


    /**
     * 調整圖片縮放,目前只支援CenterCrop
     */
    private void updateShaderMatrix() {
        float scale;
        float dx = 0;
        float dy = 0;

        mShaderMatrix.set(null);

        // 調整縮放,使圖片居中
        if (mBitmapWidth * mBitmapBound.height() > mBitmapBound.width() * mBitmapHeight) {
            scale = mBitmapBound.height() / (float) mBitmapHeight;
            dx = (mBitmapBound.width() - mBitmapWidth * scale) * 0.5f;
        } else {
            scale = mBitmapBound.width() / (float) mBitmapWidth;
            dy = (mBitmapBound.height() - mBitmapHeight * scale) * 0.5f;
        }

        Log.d(TAG, "updateShaderMatrix: scale >>> " + scale);
        mShaderMatrix.setScale(scale, scale);
        // TODO: 16-10-15 http://chroya.iteye.com/blog/713869
        // 回到中心點,便於下次縮放
        mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBitmapBound.left, (int) (dy + 0.5f) + mBitmapBound.top);

        mShader.setLocalMatrix(mShaderMatrix);
    }

onDraw

 @Override
    protected void onDraw(Canvas canvas) {
        if (mBitmap == null) {
            super.onDraw(canvas);
        }
        Log.d(TAG, "onDraw: centerX >>> " + mBitmapBound.centerX() + " centerY >>> " + mBitmapBound.centerY());
        canvas.drawCircle(mBitmapBound.centerX(), mBitmapBound.centerY(), mRadius, mFillPaint);
        // 繪製邊框
        canvas.drawCircle(mBorderBound.centerX(), mBorderBound.centerY(), mRadius, mBoundPaint);
    }

完整程式碼


/**
 * Created by shixi_tianrui1 on 16-10-7.
 * 顯示圓形圖片的ImageView
 */

public class CircleImageView extends ImageView {

    private static final String TAG = "LOGGER";

    private BitmapShader mShader;
    private Paint mFillPaint; // 繪圖
    private Paint mBoundPaint; // 繪製圓邊

    private Bitmap mBitmap;
    private Drawable mDrawable;

    private int mBorderColor;       // 邊框顏色
    private float mBorderWidth;     // 邊框寬度

    private RectF mBorderBound = new RectF();
    private RectF mBitmapBound = new RectF();
    private Matrix mShaderMatrix = new Matrix();

    private int mRadius;
    private int mBitmapWidth;
    private int mBitmapHeight;

    private static final float DEFAULT_BORDER_WIDTH = 5;

    public CircleImageView(Context context) {
        this(context, null);
    }

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

    public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = getResources().obtainAttributes(attrs, R.styleable.CircleImageView);
        mBorderColor = a.getColor(R.styleable.CircleImageView_borderColor, Color.BLUE);
        mBorderWidth = a.getDimension(R.styleable.CircleImageView_borderWidth, DEFAULT_BORDER_WIDTH);
        mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_borderWidth, 20);
        a.recycle();
    }

    private void init() {
        getBitmapFromDrawable();
        if (mBitmap == null) {
            return;
        }
        mShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

        // bitmap paint
        mFillPaint = new Paint();
        mFillPaint.setAntiAlias(true);
        mFillPaint.setStyle(Paint.Style.FILL);
        mFillPaint.setShader(mShader);

        // border paint
        mBoundPaint = new Paint();
        mBoundPaint.setAntiAlias(true);
        mBoundPaint.setStyle(Paint.Style.STROKE);
        mBoundPaint.setStrokeWidth(mBorderWidth);
        mBoundPaint.setColor(mBorderColor);

        // border rectF
        mBorderBound.set(calculateBitmapBound());

        // bitmap rectF
        mBitmapBound.set(calculateBitmapBound());
        mBitmapBound.inset(mBorderWidth - 10, mBorderWidth - 10);
        updateShaderMatrix();

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        init();
    }

    /**
     * 計算Bitmap邊距
     */
    private RectF calculateBitmapBound() {
        int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
        int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();
        int sideLength = Math.min(availableWidth, availableHeight); // 可用的直徑
        mRadius = sideLength / 2;

        int left = getPaddingLeft() + (availableWidth - sideLength) / 2;
        int top = getPaddingTop() + (availableHeight - sideLength) / 2;

        Log.d(TAG, "calculateBitmapBound: left >>> " + left + " top >>> " + top + " right >>> "
                + (left + sideLength) + " right >>> " + top + " bottom >>> " + (top + sideLength));
        return new RectF(left, top, left + sideLength, top + sideLength);
    }


    private Bitmap getBitmapFromDrawable() {
        Drawable drawable = getDrawable();
        if (drawable instanceof BitmapDrawable) {
            mBitmap = ((BitmapDrawable) drawable).getBitmap();
            mBitmapWidth = mBitmap.getWidth();
            mBitmapHeight = mBitmap.getHeight();
            return mBitmap;
        }
        return null;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mBitmap == null) {
            super.onDraw(canvas);
        }
        Log.d(TAG, "onDraw: centerX >>> " + mBitmapBound.centerX() + " centerY >>> " + mBitmapBound.centerY());
        canvas.drawCircle(mBitmapBound.centerX(), mBitmapBound.centerY(), mRadius, mFillPaint);
        // 繪製邊框
        canvas.drawCircle(mBorderBound.centerX(), mBorderBound.centerY(), mRadius, mBoundPaint);
    }


    /**
     * 調整圖片縮放,目前只支援CenterCrop
     */
    private void updateShaderMatrix() {
        float scale;
        float dx = 0;
        float dy = 0;

        mShaderMatrix.set(null);

        // 調整縮放,使圖片居中
        if (mBitmapWidth * mBitmapBound.height() > mBitmapBound.width() * mBitmapHeight) {
            scale = mBitmapBound.height() / (float) mBitmapHeight;
            dx = (mBitmapBound.width() - mBitmapWidth * scale) * 0.5f;
        } else {
            scale = mBitmapBound.width() / (float) mBitmapWidth;
            dy = (mBitmapBound.height() - mBitmapHeight * scale) * 0.5f;
        }

        Log.d(TAG, "updateShaderMatrix: scale >>> " + scale);
        mShaderMatrix.setScale(scale, scale);
        // TODO: 16-10-15 http://chroya.iteye.com/blog/713869
        // 回到中心點,便於下次縮放
        mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBitmapBound.left, (int) (dy + 0.5f) + mBitmapBound.top);

        mShader.setLocalMatrix(mShaderMatrix);
    }
}

目前仍有點問題,解決後會及時更新

相關推薦

no