带有动态圆环的圆形图片控件DynamicAvatarView

效果图


现在大部分的app上难免会使用到圆形头像,所以今天我给大家分享一个单独使用的,并且周围带有圆环动画的花哨圆形头像控件,本控件是在圆形头像控件基础上实现的,只是在其周围再画一些不同大小的圆而已,就可以实现如图的效果
圆形头像的基本原理是将设置的资源文件转化成Bitmap,然后通过BitmapShader类将Bitmap成为Paint的渲染器,然后在onDraw()中通过canvas.drawCircle(rx,ry,radius,paint);画布上画圆,而这个圆就是形成了圆形头像。
在xml中通过src设置的资源文件在ImageView的setImageDrawable(drawable)方法中可以得到Drawable类型的图像,然后再将Drawable转成Bitmap就可以了

public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        mBitmap = getBitmapFromDrawable(drawable);
        setup();
}
private Bitmap getBitmapFromDrawable(Drawable drawable) {

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

        if (drawable instanceof BitmapDrawable) {
            //从bitmap中间裁剪出最大的正方形
            Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
            return getMaxSquareCenter(bitmap);
            //return ((BitmapDrawable) drawable).getBitmap();
        }

        try {
            Bitmap bitmap;

            if (drawable instanceof ColorDrawable) {
                bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
            } else {
                int min = Math.min(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
                bitmap = Bitmap.createBitmap(min, min, BITMAP_CONFIG);
            }

            Canvas canvas = new Canvas(bitmap);
            int left,top,right,buttom;
            int width = canvas.getWidth();
            int height = canvas.getHeight();
            int abs = Math.abs(width - height);
            if(width <= height){
                left = 0;
                top = (height - abs) / 2;
                right = width;
                buttom = height - top;
            }else{
                left = (width - abs) / 2;
                top = 0;
                right = width - left;
                buttom = height;
            }
            //drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.setBounds(left, top, right, buttom);
            drawable.draw(canvas);
            return bitmap;
        } catch (OutOfMemoryError e) {
            return null;
        }
    }
/**
     * 从bitmap中间裁剪出最大的正方形
     * @param bitmap
     * @return
     */
    private Bitmap getMaxSquareCenter(Bitmap bitmap){
        int w = bitmap.getWidth(); // 得到图片的宽,高
        int h = bitmap.getHeight();
        int cropWidth = w >= h ? h : w;// 裁切后所取的正方形区域边长
        return Bitmap.createBitmap(bitmap, (w - cropWidth)/2 , (h - cropWidth)/2, cropWidth, cropWidth, null, false);
    }
获取到Bitmap对象后就可以将Bitmap缩小一倍后,在将其画在画布上,这样就有地方来画周围的圆环了。

private void updateShaderMatrix() {
        float scale;
        float dx = 0;
        float dy = 0;

        mShaderMatrix.set(null);

        if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
            scale = mDrawableRect.height() / (float) mBitmapHeight / 2;  //将图片缩放在正中间 缩小一倍
            dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
        } else {
            scale = mDrawableRect.width() / (float) mBitmapWidth / 2; //将图片缩放在正中间 缩小一倍
            dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
        }

        mShaderMatrix.setScale(scale , scale );
	//在x轴上平移mDrawableRadius,就在正中间了
        mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth + mDrawableRadius, (int) (dy + 0.5f) + mBorderWidth);

        mBitmapShader.setLocalMatrix(mShaderMatrix);
    }
下面就是画图片周围的圆环了,就是在图片的外围画两个圆,一个半径大点,颜色浅点,一个半径小点,颜色深点就可以了,然后通过Handler通过延时操作,不断的改变两个圆的半径大小和颜色的深浅,重绘就可以了

 private float mChangeRateBorder;//记录外圆执行动画时半径变化率
    private float mChangeRateOuter;//记录内圆执行动画时半径变化率
    private float mChangeRateInner;//记录图片边框执行动画时半径变化率
    private float mChangeRange;//变化范围,View半径的1/6 
//*******执行动画*******//
    //外圆执行动画时半径变化率
    private float mRateOuter[] = {
            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
            0,0.1f,0.2f,0.3f,0.4f,0.5f,0.6f,0.7f,0.8f,0.9f,1.0f
            ,0.92f,0.88f,0.85f,0.82f,0.76f,0.72f,0.68f,0.60f,0.54f,0.48f,
            0.40f,0.33f,0.28f,0.20f};
    //内圆执行动画时半径变化率
    private float mRateInner[] = {
            -1,-1,-1,-1,-1,
            0,0.1f,0.2f,0.3f,0.4f,0.5f,0.6f,0.7f,0.8f,0.9f,1.0f
            ,0.92f,0.88f,0.84f,0.80f,0.72f,0.67f,0.60f,0.54f,0.48f,-1f
            ,-1f,-1f,-1f,-1f,-1f,-1f,-1f,-1f,-1f};
    //图片边框执行动画时半径变化率
    private float mRateBorder[] = {
            0,0.1f,0.2f,0.3f,0.4f,0.5f,0.6f,0.7f,0.8f,0.9f,1.0f
            ,0.92f,0.90f,0.84f,0.78f,0.72f,0.64f,0.58f,-1f,-1f,-1f
            ,-1f,-1f,-1f,-1f,-1f,-1f,-1f,-1f,-1f,-1f
            ,-1f,-1f,-1f,-1f};

    private int mRateIndex;//动画变化率的索引
Handler不断改变半径的变化率和画笔的颜色

/**
     * 按住执行动画
     */
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            int index = mRateIndex ++;
            mChangeRateBorder = mRateBorder[(index)% mRateBorder.length];
            setPaintCorlor(mBorderPaint,mChangeRateBorder,DEFAULT_BORDER_COLOR);
            setPaintAlpha(mBorderPaint,(index)% mRateBorder.length,mRateBorder);
            mChangeRateOuter = mRateOuter[(index) % mRateOuter.length];
            setPaintCorlor(mOuterPaint,mChangeRateOuter,mOuterPaintColor);
            setPaintAlpha(mOuterPaint,(index) % mRateOuter.length,mRateOuter);
            mChangeRateInner = mRateInner[(index) % mRateInner.length];
            setPaintCorlor(mInnerPaint,mChangeRateInner,mInnerPaintColor);
            setPaintAlpha(mInnerPaint,(index) % mRateInner.length,mRateInner);

            //System.out.println("---------mChangeRate:"+mChangeRateBorder);
            invalidate();
            mHandler.removeCallbacksAndMessages(null);
            mHandler.sendEmptyMessageDelayed(0,30);
        }
    };
每执行一次handleMessage()就会触发(invalidate())View重绘,onDraw中不断的重绘,只需改变每个Circle的半径即可

@Override
    protected void onDraw(Canvas canvas) {

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

        //画动画的图形
        canvas.drawCircle(getWidth() / 2,getHeight() / 2,getChangeRadiusOuter(mOuterRadius),mOuterPaint);
        canvas.drawCircle(getWidth() / 2,getHeight() / 2,getChangeRadiusInner(mInnerRadius),mInnerPaint);

        canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint);
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, getChangeRadiusBorder(mBorderRadius), mBorderPaint);
    }
根据Handler中给的变化率来计算每个Circle的半径
private float getChangeRadiusBorder(float radius){

        return mChangeRateBorder * mChangeRange + radius;

    }
    private float getChangeRadiusOuter(float radius){

        return mChangeRateOuter * mChangeRange + radius;

    }
    private float getChangeRadiusInner(float radius){

        return mChangeRateInner * mChangeRange + radius;

    }
这样在不断的向Handler发送消息时,也就会不断的触发重绘,不断改变外围圆的大小,形成上图所见的动画效果
如下四个方法,就是来控制圆环所展示的不同状态

/**
     * 开始动画
     */
    public void startAnim(){
	//让外围的圆环动起来
        mHandler.sendEmptyMessageDelayed(0,30);

    }
    /**
     * 停止动画
     */
    public void stopAnim(){
	//停止外圆环的动画,展示默认的大小
        mHandler.removeCallbacksAndMessages(null);
        mChangeRateBorder = 0;
        mChangeRateOuter = 0;
        mChangeRateInner = 0;

        initAnimColor();

        enterAnim();
    }
    /**
     * 进入动画
     */
    public void enterAnim(){
	//展示外圆环,显示默认大小
        mHandlerEnter.sendEmptyMessage(0);
    }

    /**
     * 退出动画
     */
    public void exitAnim(){
	//隐藏外圆环
        mHandlerExit.sendEmptyMessage(0);
    }

好了,动态头像到这基本就实现了,进入动画和退出动画的代码就不贴出来分析了,如果发现bug或者有任何意见欢迎留言。

完整源码

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.widget.ImageView;

/**
 * Created by cj_28 on 2016/10/15.
 */
public class DynamicAvatarView extends ImageView {

    private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;

    private static final int COLORDRAWABLE_DIMENSION = 1;
    private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;

    private Bitmap mBitmap;
    private BitmapShader mBitmapShader;

    private final Matrix mShaderMatrix = new Matrix();
    private final Paint mBitmapPaint = new Paint();
    private final Paint mBorderPaint = new Paint();
    private final Paint mOuterPaint = new Paint();
    private final Paint mInnerPaint = new Paint();

    private static final int DEFAULT_BORDER_WIDTH = 3;
    private static final int DEFAULT_BORDER_COLOR = Color.WHITE;
    private static final int OUTER_PAINT_COLOR = Color.parseColor("#55FFFFFF");
    private static final int INNER_PAINT_COLOR = Color.parseColor("#66FFFFFF");

    private int mBorderColor = DEFAULT_BORDER_COLOR;
    private int mBorderWidth = DEFAULT_BORDER_WIDTH;

    private int mOuterPaintColor = OUTER_PAINT_COLOR;
    private int mInnerPaintColor = INNER_PAINT_COLOR;

    private int mBitmapWidth;
    private int mBitmapHeight;

    private final RectF mDrawableRect = new RectF();
    private final RectF mBorderRect = new RectF();

    private float mDrawableRadius;//显示的图片
    private float mBorderRadius;//..//显示的图片上的边框
    private float mOuterRadius;//外层动画
    private float mInnerRadius;//..//内层动画

    private float mRealDrawableRadius;//这是View没有被缩放之前的mDrawableRadius的半径
    private float mRealBorderRadius;//..

    private boolean mReady;
    private boolean mSetupPending;

    private float mChangeRateBorder;//记录外圆执行动画时半径变化率
    private float mChangeRateOuter;//记录内圆执行动画时半径变化率
    private float mChangeRateInner;//记录图片边框执行动画时半径变化率
    private float mChangeRange;//变化范围,View半径的1/6

    //*******执行动画*******//
    //外圆执行动画时半径变化率
    private float mRateOuter[] = {
            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
            0,0.1f,0.2f,0.3f,0.4f,0.5f,0.6f,0.7f,0.8f,0.9f,1.0f
            ,0.92f,0.88f,0.85f,0.82f,0.76f,0.72f,0.68f,0.60f,0.54f,0.48f,
            0.40f,0.33f,0.28f,0.20f};
    //内圆执行动画时半径变化率
    private float mRateInner[] = {
            -1,-1,-1,-1,-1,
            0,0.1f,0.2f,0.3f,0.4f,0.5f,0.6f,0.7f,0.8f,0.9f,1.0f
            ,0.92f,0.88f,0.84f,0.80f,0.72f,0.67f,0.60f,0.54f,0.48f,-1f
            ,-1f,-1f,-1f,-1f,-1f,-1f,-1f,-1f,-1f};
    //图片边框执行动画时半径变化率
    private float mRateBorder[] = {
            0,0.1f,0.2f,0.3f,0.4f,0.5f,0.6f,0.7f,0.8f,0.9f,1.0f
            ,0.92f,0.90f,0.84f,0.78f,0.72f,0.64f,0.58f,-1f,-1f,-1f
            ,-1f,-1f,-1f,-1f,-1f,-1f,-1f,-1f,-1f,-1f
            ,-1f,-1f,-1f,-1f};

    //private int mColor[] = {0x55FFFFFF,0x44FFFFFF,0x33FFFFFF,0x22FFFFFF,0x11FFFFFF,0x00FFFFFF,0x00FFFFFF,0x00FFFFFF,0x00FFFFFF,0x00FFFFFF};
    private int mRateIndex;//动画变化率的索引

    //*******进入动画*******//
    //外圆执行动画时半径变化率
    private float mRateOuterEnter[] = {
            -2,-2,//外圆要缩小2个mChangeRange才会完全隐藏
            -2,-2,-2,-2,-2,
            -0.8f,-0.6f,-0.4f,-0.2f,-0.1f,
            0,0.1f,0.2f,0.3f,0.4f,0.5f
            ,0.44f,0.4f,0.35f,0.3f,0.25f
            ,0.20f,0.15f,0.1f,0.0f};
    //内圆执行动画时半径变化率
    private float mRateInnerEnter[] = {
            -1,-1,//外圆要缩小1个mChangeRange才会完全隐藏
            -0.8f,-0.6f,-0.4f,-0.2f,-0.1f,
            0,0.1f,0.2f,0.3f,0.35f,0.4f
            ,0.45f,0.5f,0.45f,0.4f,0.35f
            ,0.3f,0.25f,0.2f,0.15f,0.1f
            ,0.05f,0f,0f,0f};
    private int mRateIndexEnter;//进入动画变化率的索引

    //*******退出动画*******//
    //外圆执行动画时半径变化率
    private float mRateOuterExit[] = {

            0.0f,-0.2f,-0.4f,-0.6f,-0.8f
            ,-1f,-1.2f,-1.4f,-1.6f,-1.8f
            ,-2f};
    //内圆执行动画时半径变化率
    private float mRateInnerExit[] = {

            0.0f,-0.1f,-0.2f,-0.3f,-0.4f
            ,-0.5f,-0.6f,-0.7f,-0.8f,-0.9f
            ,-1f};
    private int mRateIndexExit;//进入动画变化率的索引


    /**
     * 按住执行动画
     */
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            int index = mRateIndex ++;
            mChangeRateBorder = mRateBorder[(index)% mRateBorder.length];
            setPaintCorlor(mBorderPaint,mChangeRateBorder,DEFAULT_BORDER_COLOR);
            setPaintAlpha(mBorderPaint,(index)% mRateBorder.length,mRateBorder);
            mChangeRateOuter = mRateOuter[(index) % mRateOuter.length];
            setPaintCorlor(mOuterPaint,mChangeRateOuter,mOuterPaintColor);
            setPaintAlpha(mOuterPaint,(index) % mRateOuter.length,mRateOuter);
            mChangeRateInner = mRateInner[(index) % mRateInner.length];
            setPaintCorlor(mInnerPaint,mChangeRateInner,mInnerPaintColor);
            setPaintAlpha(mInnerPaint,(index) % mRateInner.length,mRateInner);

            //System.out.println("---------mChangeRate:"+mChangeRateBorder);
            invalidate();
            mHandler.removeCallbacksAndMessages(null);
            mHandler.sendEmptyMessageDelayed(0,30);
        }
    };

    private Handler mHandlerEnter = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            int index = mRateIndexEnter ++;
            if(index >= mRateOuterEnter.length) {
                mRateIndexEnter = 0;
                mHandlerEnter.removeCallbacksAndMessages(null);
                return;
            }

            mChangeRateOuter = mRateOuterEnter[(index) % mRateOuterEnter.length];

            mChangeRateInner = mRateInnerEnter[(index) % mRateInnerEnter.length];

            invalidate();
            mHandlerEnter.removeCallbacksAndMessages(null);
            mHandlerEnter.sendEmptyMessageDelayed(0,20);
        }
    };

    private Handler mHandlerExit = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            int index = mRateIndexExit ++;
            if(index >= mRateOuterExit.length) {
                mRateIndexExit = 0;
                mHandlerExit.removeCallbacksAndMessages(null);
                return;
            }

            mChangeRateOuter = mRateOuterExit[(index) % mRateOuterExit.length];

            mChangeRateInner = mRateInnerExit[(index) % mRateInnerExit.length];

            invalidate();
            mHandlerExit.removeCallbacksAndMessages(null);
            mHandlerExit.sendEmptyMessageDelayed(0,20);
        }
    };

    /**
     * 设置outer和inner的画笔颜色
     * @param paint
     * @param rate
     * @param color
     */
    private void setPaintCorlor(Paint paint,float rate,int color){
        if(rate < 0){
            paint.setColor(Color.TRANSPARENT);
        }else{
            paint.setColor(color);
        }
    }

    /**
     * 设置透明度
     * @param paint
     * @param index
     * @param rate
     */
    private void setPaintAlpha(Paint paint,int index,float[] rate){
        int pre = index -1;
        if(pre >= 0 ){
            if(rate[pre] > rate[index] && rate[index] > 0){
                int color = paint.getColor();

                int colorTransparent = color & 0xff000000;
                int colorValue = color & 0x00ffffff;
                colorTransparent = colorTransparent >>> 7;
                paint.setColor((int)(rate[index] * colorTransparent) << 7 | colorValue);

            }
        }
    }

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

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

    }

    public DynamicAvatarView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        super.setScaleType(SCALE_TYPE);

        //可以执行了
        mReady = true;

        if (mSetupPending) {
            setup();
            mSetupPending = false;
        }
    }

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

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int size = Math.min(widthSize, heightSize);

        super.onMeasure(MeasureSpec.makeMeasureSpec(size,widthMode), MeasureSpec.makeMeasureSpec(size,heightMode));
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

        super.onLayout(changed, left, top, right, bottom);
        enterAnim();
    }

    @Override
    protected void onDraw(Canvas canvas) {

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

        //画动画的图形
        canvas.drawCircle(getWidth() / 2,getHeight() / 2,getChangeRadiusOuter(mOuterRadius),mOuterPaint);
        canvas.drawCircle(getWidth() / 2,getHeight() / 2,getChangeRadiusInner(mInnerRadius),mInnerPaint);

        canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint);
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, getChangeRadiusBorder(mBorderRadius), mBorderPaint);
    }

    private float getChangeRadiusBorder(float radius){

        return mChangeRateBorder * mChangeRange + radius;

    }
    private float getChangeRadiusOuter(float radius){

        return mChangeRateOuter * mChangeRange + radius;

    }
    private float getChangeRadiusInner(float radius){

        return mChangeRateInner * mChangeRange + radius;

    }

    private void initAnimColor(){
        mOuterPaint.setStyle(Paint.Style.FILL);
        mOuterPaint.setAntiAlias(true);
        mOuterPaint.setColor(mOuterPaintColor);
        mInnerPaint.setStyle(Paint.Style.FILL);
        mInnerPaint.setAntiAlias(true);
        mInnerPaint.setColor(mInnerPaintColor);
        //图片边框(默认白色)
        mBorderPaint.setColor(mBorderColor);

        mOuterRadius = mRealBorderRadius / 6 * 5;
        mInnerRadius = mRealBorderRadius / 6 * 4;
        mChangeRange = mRealBorderRadius / 6;
        mRateIndex = 0;
    }

    /**
     * 开始动画
     */
    public void startAnim(){
        mHandler.sendEmptyMessageDelayed(0,30);

    }
    /**
     * 停止动画
     */
    public void stopAnim(){
        mHandler.removeCallbacksAndMessages(null);
        mChangeRateBorder = 0;
        mChangeRateOuter = 0;
        mChangeRateInner = 0;
//        mBorderPaint.setColor(DEFAULT_BORDER_COLOR);
//        mOuterPaint.setColor(mOuterPaintColor);
//        mInnerPaint.setColor(mInnerPaintColor);
//        mRateIndex = 0;
        initAnimColor();

        //invalidate();
        enterAnim();
    }
    /**
     * 进入动画
     */
    public void enterAnim(){
        mHandlerEnter.sendEmptyMessage(0);
    }

    /**
     * 退出动画
     */
    public void exitAnim(){
        mHandlerExit.sendEmptyMessage(0);
    }

    /**
     * 设置外圆动画的颜色
     * @param outerPaintColor
     */
    public void setOuterPaintColor(int outerPaintColor) {
        if (outerPaintColor == mOuterPaintColor) {
            return;
        }
        mOuterPaintColor = outerPaintColor;
        mOuterPaint.setColor(mOuterPaintColor);
        invalidate();
    }

    /**
     * 设置内圆动画的颜色
     * @param innerPaintColor
     */
    public void setInnerPaintColor(int innerPaintColor) {
        if (innerPaintColor == mInnerPaintColor) {
            return;
        }
        mInnerPaintColor = innerPaintColor;
        mInnerPaint.setColor(mInnerPaintColor);
        invalidate();
    }

    /**
     * 设置图片边框的颜色
     * @param borderColor
     */
    public void setBorderColor(int borderColor) {
        if (borderColor == mBorderColor) {
            return;
        }

        mBorderColor = borderColor;
        mBorderPaint.setColor(mBorderColor);
        invalidate();
    }

    /**
     * 设置图片边框的宽度
     * @param borderWidth
     */
    public void setBorderWidth(int borderWidth) {
        if (borderWidth == mBorderWidth) {
            return;
        }

        mBorderWidth = borderWidth;
        setup();
    }

    @Override
    public ScaleType getScaleType() {
        return SCALE_TYPE;
    }

    @Override
    public void setScaleType(ScaleType scaleType) {
        if (scaleType != SCALE_TYPE) {
            throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //只有在此方法中调用setup,setup中的getWidth方法得到的值才不会是0,
        setup();
    }

    @Override
    public void setImageBitmap(Bitmap bm) {
        super.setImageBitmap(bm);
        mBitmap = getMaxSquareCenter(bm);
        setup();
    }

    /**
     * mxl中设置src就会走此方法
     * @param drawable
     */
    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        mBitmap = getBitmapFromDrawable(drawable);
        setup();
    }

    @Override
    public void setImageResource(int resId) {
        super.setImageResource(resId);
        mBitmap = getBitmapFromDrawable(getDrawable());
        setup();
    }

    /**
     * 从bitmap中间裁剪出最大的正方形
     * @param bitmap
     * @return
     */
    private Bitmap getMaxSquareCenter(Bitmap bitmap){
        int w = bitmap.getWidth(); // 得到图片的宽,高
        int h = bitmap.getHeight();
        int cropWidth = w >= h ? h : w;// 裁切后所取的正方形区域边长
        return Bitmap.createBitmap(bitmap, (w - cropWidth)/2 , (h - cropWidth)/2, cropWidth, cropWidth, null, false);
    }

    private Bitmap getBitmapFromDrawable(Drawable drawable) {

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

        if (drawable instanceof BitmapDrawable) {
            //从bitmap中间裁剪出最大的正方形
            Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
            return getMaxSquareCenter(bitmap);
            //return ((BitmapDrawable) drawable).getBitmap();
        }

        try {
            Bitmap bitmap;

            if (drawable instanceof ColorDrawable) {
                bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
            } else {
                int min = Math.min(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
                bitmap = Bitmap.createBitmap(min, min, BITMAP_CONFIG);
            }

            Canvas canvas = new Canvas(bitmap);
            int left,top,right,buttom;
            int width = canvas.getWidth();
            int height = canvas.getHeight();
            int abs = Math.abs(width - height);
            if(width <= height){
                left = 0;
                top = (height - abs) / 2;
                right = width;
                buttom = height - top;
            }else{
                left = (width - abs) / 2;
                top = 0;
                right = width - left;
                buttom = height;
            }
            //drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.setBounds(left, top, right, buttom);
            drawable.draw(canvas);
            return bitmap;
        } catch (OutOfMemoryError e) {
            return null;
        }
    }

    private void setup() {
        //只有执行过构造函数之后,所有的成员才被初始化完毕
       if (!mReady) {
            mSetupPending = true;
            return;
        }

        if (mBitmap == null) {
            return;
        }

        mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

        mBitmapPaint.setAntiAlias(true);
        mBitmapPaint.setShader(mBitmapShader);

        mBorderPaint.setStyle(Paint.Style.STROKE);
        mBorderPaint.setAntiAlias(true);
        mBorderPaint.setColor(mBorderColor);
        mBorderPaint.setStrokeWidth(mBorderWidth);

        mBitmapHeight = mBitmap.getHeight();
        mBitmapWidth = mBitmap.getWidth();
        //图片边框设置的范围
        mBorderRect.set(0, 0, getWidth(), getHeight());
        mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2, (mBorderRect.width() - mBorderWidth) / 2) / 2;
        mRealBorderRadius = 2 * mBorderRadius;
        //图片显示的范围
        mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth);
        //让图片显示的范围是控件大小的一半
        mDrawableRadius = Math.min(mDrawableRect.height() / 2, mDrawableRect.width() / 2) / 2;
        mRealDrawableRadius = 2 * mDrawableRadius;

        updateShaderMatrix();
        initAnimColor();
        invalidate();
    }

    private void updateShaderMatrix() {
        float scale;
        float dx = 0;
        float dy = 0;

        mShaderMatrix.set(null);

        if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
            scale = mDrawableRect.height() / (float) mBitmapHeight / 2;  //将图片缩放在正中间
            dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
        } else {
            scale = mDrawableRect.width() / (float) mBitmapWidth / 2;
            dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
        }

        mShaderMatrix.setScale(scale , scale );
        mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth + mDrawableRadius, (int) (dy + 0.5f) + mBorderWidth);

        mBitmapShader.setLocalMatrix(mShaderMatrix);
    }

}

参考:https://github.com/hdodenhof/CircleImageView


  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值