Android — 自定义圆形 ImageView 控件

368 查看

需求描述

越来越多的社交软件通过圆形外框来展现用户头像,因此我们需要将方形源文件以圆形来展示。

实现 src 圆形化显示

完整代码

public class CircleImageView extends ImageView {
    
    private static final String TAG = "CircleImageView";
    private Shader mShader;
    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

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

    @Override
    protected void onDraw(Canvas canvas) {
        Bitmap rawBitmap = getBitmap(getDrawable());
        if (rawBitmap != null) {
            int viewWidth = getWidth();
            int viewHeight = getHeight();
            int viewMinSize = Math.min(viewWidth, viewHeight);
            if (mShader == null) {
                mShader = new BitmapShader(rawBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            }
            mPaint.setShader(mShader);
            float radius = viewMinSize / 2.0f;
            canvas.drawCircle(radius, radius, radius, mPaint);
        } else {
            super.onDraw(canvas);
        }
    }

    private Bitmap getBitmap(Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();
        } else if (drawable instanceof ColorDrawable) {
            Rect rect = drawable.getBounds();
            int width = rect.width();
            int height = rect.height();
            int color = ((ColorDrawable) drawable).getColor();
            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            canvas.drawARGB(Color.alpha(color), Color.red(color), Color.green(color),
                    Color.blue(color));
            return bitmap;
        } else {
            return null;
        }
    }
}

onDraw() 方法部分注释

    protected void onDraw(Canvas canvas) {
        // 通过 getBitMap 方法获取到原始 Bitmap
        Bitmap rawBitmap = getBitmap(getDrawable());
        // Drawable 是 Bitmap 或 Color
        if (rawBitmap != null) {
            int viewWidth = getWidth();
            int viewHeight = getHeight();
            // 由于是圆形,所以需要两者中的 Min。
            int viewMinSize = Math.min(viewWidth, viewHeight);
            // 判断 Shader 是否已经初始化过,避免绘制过程卡顿。
            if (mShader == null) {
                // 把原始 Bitmap 给 Shader,模式为拉伸。
                mShader = new BitmapShader(rawBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            }
            mPaint.setShader(mShader);
            // 得到圆形半径
            float radius = viewMinSize / 2.0f;
            // 确定绘制 Circle 的中心点、半径和 Paint
            canvas.drawCircle(radius, radius, radius, mPaint);
        } else {
            super.onDraw(canvas);
        }
    }

getBitmap() 方法部分注释

    private Bitmap getBitmap(Drawable drawable) {
        // 如果是 Bitmap 类的 Drawable
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();
        } else if (drawable instanceof ColorDrawable) {
            Rect rect = drawable.getBounds();
            int width = rect.width();
            int height = rect.height();
            int color = ((ColorDrawable) drawable).getColor();
            // 创建 ARGB_8888 格式的 Bitmap
            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            // 绘制目标颜色,从而把颜色转换为 Bitmap
            canvas.drawARGB(Color.alpha(color), Color.red(color), Color.green(color),
                    Color.blue(color));
            return bitmap;
        } else {
            return null;
        }
    }

存在的问题

  1. 对图片资源不会自动缩放,如果是用户自行上传的图片则可能造成资源浪费或者 OOM,但本次需求是系统自带的图标圆形化,所以不需要实现。如果需要实现则可以用 Matrix 实现,可以见文末参考处;

  2. 如果需要加上背景,那么 Background 依然是方形的,而不是圆形。


references:
http://www.cnblogs.com/goagen...
http://www.jianshu.com/p/ed5d...