一般在项目中,我们用到的圆形头像都是采用自定义视图的方式,这种圆形头像一般分为普通的圆形头像、带边框的圆形图像、随机背景头像,在上一篇Android圆形图像的绘制(一)中,提到了圆形头像绘制的基本方法,这遍文章主要是用到上篇文章中SRC_IN这个方法,下面看一下效果图。

首先,创建一个类CircleImageView,让它继承ImageView,代码如下:

    public class CircleImageView extends ImageView {        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);        }        @Override        protected void onDraw(Canvas canvas) {            super.onDraw(canvas);        }    }
在创建自定义视图时,一般都会在res/values/attrs.xml创建declare-styleable,如果values下面没有attrs.xml这个文件,可以自己新建,将新建的declare-styleable命名为CircleImageView。为了得到上图中的效果,需要知道边缘宽度、边缘颜色、随机头像的背景色、随机背景上展示的文字,以及文字的大小,代码如下:

                                                
此时,需要在CircleImageView的构造函数里,获取attrs.xml名为CircleImageView的属性,在获取属性的时候,需要定位文本字体大小,和颜色的默认值,边缘宽度默认值为0,也就是没有边缘。代码如下:

    public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        //#5AC3B2        int defaultColor = getResources().getColor(R.color.colorGreen);        //14sp        int defaultTextSize = getResources().getDimensionPixelSize(R.dimen.dimen_default_text_size);        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyleAttr, 0);        mStrokeWidth = typedArray.getDimensionPixelSize(R.styleable.CircleImageView_stroke_width, 0);        mStrokeColor = typedArray.getColor(R.styleable.CircleImageView_stroke_color, defaultColor);        mTextSize = typedArray.getDimensionPixelSize(R.styleable.CircleImageView_text_size, defaultTextSize);        mBackground = typedArray.getColor(R.styleable.CircleImageView_random_backgroud, defaultColor);        mText = typedArray.getString(R.styleable.CircleImageView_text);        //一定要记得回收        typedArray.recycle();    }

定义一个mBitmap的全局变量,并重写setImageResource、setImageDrawable、setImageBitmap这三个方法,获取位图信息,并进行重新的绘制,代码如下:

    /**     * 绘制图片的位图     */    private Bitmap mBitmap;
    @Override    public void setImageResource(int resId) {        super.setImageResource(resId);        mBitmap = getBitmapFromDrawable(getDrawable());        invalidate();    }    @Override    public void setImageDrawable(Drawable drawable) {        super.setImageDrawable(drawable);        mBitmap = getBitmapFromDrawable(drawable);        invalidate();    }    @Override    public void setImageBitmap(Bitmap bm) {        super.setImageBitmap(bm);        mBitmap = bm;        invalidate();    }
 /**     * 获取bitmap     *     * @param drawable     * @return     */    private Bitmap getBitmapFromDrawable(Drawable drawable) {        if (drawable == null) {            return null;        }        if (drawable instanceof BitmapDrawable) {            return ((BitmapDrawable) drawable).getBitmap();        }        try {            Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);            Canvas canvas = new Canvas(bitmap);            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());            drawable.draw(canvas);            return bitmap;        } catch (OutOfMemoryError e) {            return null;        }    }
运行代码,效果图如下:


运行出来,什么效果都没有,是因为没有实现onDraw这个方法,在实现onDraw之前,需要重写onSizeChanged方法,获取到当前view的长宽,代码如下:

    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        mWidth = w;        mHeight = h;    }
下面看下onDraw的实现,代码如下:

    @Override    protected void onDraw(Canvas canvas) {        //一定要注释掉,否则圆形图像没法生效//        super.onDraw(canvas);        if (mWidth > 0 && mHeight > 0) {            Bitmap bitmap = createCircleBitmapForSRC_IN(canvas);            if (bitmap != null) {                canvas.drawBitmap(bitmap, 0, 0, new Paint());            }        }    }
 /**     * 创建圆形图像     * @param targetCanvs     * @return     */    private Bitmap createCircleBitmapForSRC_IN(Canvas targetCanvs) {        //创建一个和图片大小差不多的正方形矩阵        int size = Math.min(mWidth, mHeight);        Bitmap newBitmap = null;        if (mBitmap != null) {            int width = mBitmap.getWidth();            int height = mBitmap.getHeight();            // 对bitmap进行缩放,缩放到指定view的大小            Matrix matrix = new Matrix();            matrix.postScale((float) mWidth / width, (float) mHeight / height);            newBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width,                    height, matrix, true);        } else {            newBitmap = createRandomMaskBitmap(size);        }        if (newBitmap == null) {            return null;        }        int center = size / 2;        Paint paint = new Paint();        boolean isDrawBorder = drawCircleBorder(targetCanvs, center, paint);        Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);        Canvas canvas = new Canvas(bitmap);        if (isDrawBorder) {            paint.setColor(Color.WHITE);            paint.setStyle(Paint.Style.FILL);            canvas.scale(DEFAULT_SCALE, DEFAULT_SCALE, center, center);        }        //在矩阵中心画圆,与矩阵的四边相切        canvas.drawCircle(center, center, center, paint);        //设置Xfermode为SRC_IN        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));        //绘制图片        canvas.drawBitmap(newBitmap, 0, 0, paint);        return bitmap;    }
    /**     * 创建随机背景     * @param size     * @return     */    private Bitmap createRandomMaskBitmap(int size) {        Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);        final Paint paint = new Paint();        paint.setAntiAlias(true);// 抗锯齿        paint.setFilterBitmap(true);        paint.setColor(mBackground);        int center = size / 2;//获取画布的中心位置        //创建canvas对象,绘制随机背景        Canvas canvas = new Canvas(output);        canvas.drawCircle(center, center, center, paint);        //绘制随机背景上的文字        setText(canvas, size, paint);        return output;    }
    /**     * 绘制文本     * @param canvas     * @param size     * @param paint     */    private void setText(Canvas canvas, int size, Paint paint) {        Rect targetRect = new Rect(0, 0, size, size);        //设置绘制文本字体的颜色        paint.setColor(Color.WHITE);        //设置绘制文本的大小        paint.setTextSize(mTextSize);        //获取文本展示的居中位置        Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();        int baseline = (targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2;        paint.setTextAlign(Paint.Align.CENTER);        canvas.drawText(mText, targetRect.centerX(), baseline, paint);    }

   
/**     * 绘制边界圆     *     * @param canvas     * @param size     * @param paint     * @return     */    private boolean drawCircleBorder(Canvas canvas, int size, Paint paint) {        if (mStrokeWidth > 0) {            paint.setAntiAlias(true);            paint.setColor(mStrokeColor);            paint.setStyle(Paint.Style.STROKE);            paint.setStrokeWidth(mStrokeWidth);            canvas.drawCircle(size, size, size - mStrokeWidth, paint);            return true;        }        return false;    }

Activity的布局文件如下:

<?xml version="1.0" encoding="utf-8"?>                
在Activity里需要进行如下初始化:

MainActivity代码:

    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        CircleImageView circleImageView = (CircleImageView) findViewById(R.id.random_icon);        circleImageView.drawRandomBackground();        CircleImageView circleImageView1 = (CircleImageView) findViewById(R.id.random_icon1);        circleImageView1.drawRandomBackground();    }
CircleImageView里的drawRandomBackground方法的实现如下:

    /**     * 绘制随机背景     */    public void drawRandomBackground() {        invalidate();    }
到这里,运行代码就可以得到文章最开始的那张效果图了。

我们需要注意的问题如下:

1:onDraw方法里的super.onDraw(canvas)一定要注释掉,否则后面的绘制无法生效;

2:对位图进行绘制的时候,需要对位图进行缩放,大小跟view的大小一致;

3:在绘制边缘的时候,圆的半径要剪出边缘宽度的大小,否则边缘线会有展示不全的效果;

4:在获取文本居中的时,应该通过Paint.FontMetricsInt计算获取


Github地址
源码地址

更多相关文章

  1. android GridView学习笔记
  2. 【工利其器】必会工具之(四)Refactor篇——Android(安卓)Studio在
  3. 【转】eclipse 上调试android的自带应用方法
  4. Android之Intent传递数据的方式
  5. Android点击Button切换多个图片显示
  6. Android(安卓)如何远端调试framework和APK?
  7. Android开发中如何使用绘制图表
  8. Android(安卓)studio如何指定使用自己生成的keystore调试
  9. Android(安卓)Volley入门到精通:初识Volley的基本用法(示例,出错

随机推荐

  1. Android InstrumentationTestRunner 链接
  2. Android: android x86 in VirtualBox
  3. android从网上加载图片简单示例
  4. 关于Android重力感应器的频率的分析
  5. android使用adb命令安装软件
  6. Android(安卓)游戏引擎libgdx 如何添加万
  7. android文件读取
  8. Android EditText保留小数点后两位
  9. Android(安卓)Studio 配置使用GreenDao3.
  10. Android Q 下拉状态栏快捷开关解析