Android 自定义圆形头像

Android 自定义圆形头像

先上效果图,如下:
这里写图片描述

这是有边框的圆形ImageView的效果图,如果想没有边框或者改变边框的颜色都可以通过代码进行设置,下面直接上代码:

package com.example.admin.viewtest;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.View;

/**
 * 此类实现了圆形ImageView的功能
 */
public class CircleImageView extends View {

    private Bitmap mBitmap;
    private int mLineColor;
    private int mLineWidth;
    private Paint mPaint = new Paint();
    private Context mContext;

    public CircleImageView(Context context) {
        super(context);
        init(context, null);
    }

    public CircleImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        this.mContext = context;
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);
        BitmapDrawable drawable = (BitmapDrawable) ta.getDrawable(R.styleable.CircleImageView_src);
        if (drawable != null)
            mBitmap = drawable.getBitmap();
        mLineColor = ta.getColor(R.styleable.CircleImageView_line_color, Color.WHITE);
        mLineWidth = (int) ta.getDimension(R.styleable.CircleImageView_line_width, 0);
        squareBitmap();
        ta.recycle();
        mPaint.setAntiAlias(true);
        mPaint.setColor(mLineColor);
        mPaint.setStrokeWidth(mLineWidth);
    }

    /**
     * 将图片处理为正方形图片
     */
    private void squareBitmap() {
        if (mBitmap != null && mBitmap.getWidth() != mBitmap.getHeight()) {
            int wh = Math.min(mBitmap.getWidth(), mBitmap.getHeight());
            int num = Math.abs((mBitmap.getWidth() - mBitmap.getHeight()) / 2);
            if (mBitmap.getHeight() >= mBitmap.getWidth()) {
                mBitmap = Bitmap.createBitmap(mBitmap, 0, num, wh, wh);
            } else {
                mBitmap = Bitmap.createBitmap(mBitmap, num, 0, wh, wh);
            }
        }
    }

    @Override
    public void draw(Canvas canvas) {
        if (mBitmap != null) {
            int w = getWidth() - getPaddingLeft() - getPaddingRight();
            int h = getHeight() - getPaddingTop() - getPaddingBottom();
            int bw = mBitmap.getWidth();
            /**
             * 根据画布大小缩放图片
             */
            Matrix matrix = new Matrix();
            if (w >= h) {
                matrix.setScale(h / (float) bw, h / (float) bw);
            } else {
                matrix.setScale(w / (float) bw, w / (float) bw);
            }
            mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, bw, bw, matrix, true);
            int width = 0;
            int left;
            int top;
            /**
             * 确定图片的位置,这里考虑了设置的padding,如果不处理padding的值,那么设置的padding将失效
             */
            if (mBitmap != null)
                width = mBitmap.getWidth();
            if (w >= h) {
                left = getPaddingLeft() + Math.abs((w - h) / 2);
                top = getPaddingTop();
            } else {
                left = getPaddingLeft();
                top = getPaddingTop() + Math.abs((w - h) / 2);
            }
            canvas.drawBitmap(createCircleImage(mBitmap, width), left, top, mPaint);
            mPaint.setColor(mLineColor);
            mPaint.setStrokeWidth(mLineWidth);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setAntiAlias(true);
            canvas.drawCircle((width / 2) + left, width / 2 + top, width / 2 - mLineWidth, mPaint);
        }
    }

    /**
     * 绘制圆形图片
     *
     * @param source
     * @param min
     * @return
     */
    private Bitmap createCircleImage(Bitmap source, int min) {
        Paint p = new Paint();
        p.setAntiAlias(true);
        Bitmap target = Bitmap.createBitmap(min, min, Bitmap.Config.ARGB_8888);
        /**
         * 产生一个同样大小的画布
         */
        Canvas canvas = new Canvas(target);
        /**
         * 首先绘制圆形
         */
        canvas.drawCircle(min / 2, min / 2, min / 2 - mLineWidth, p);
        /**
         * 使用SRC_IN,参考上面的说明
         */
        p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        /**
         * 绘制图片
         */
        canvas.drawBitmap(source, 0, 0, p);
        return target;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMeasureMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthMeasureSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMeasureMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightMeasureSize = MeasureSpec.getSize(heightMeasureSpec);
        int pd = getPaddingBottom();
        int pt = getPaddingTop();
        int pl = getPaddingLeft();
        int pr = getPaddingRight();
        int width = 0;
        int height = 0;
        /**
         * 获取设置的图片的宽高
         */
        if (mBitmap != null) {
            width = mBitmap.getWidth();
            height = mBitmap.getHeight();
        }
        /**
         *当宽、高设置为wrap_content时,Mode为MeasureSpec.AT_MOST最大模式;
         *当宽、高设置为match_parent或者具体的值时,Mode为MeasureSpec.EXACTLY精确模式;
         *在测量View的宽、高时,需要对padding做处理,不然设置的padding将会失效
         */
        if (widthMeasureMode == MeasureSpec.AT_MOST && heightMeasureMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(width + pl + pr, height + pd + pt);
        } else if (widthMeasureMode == MeasureSpec.AT_MOST && heightMeasureMode == MeasureSpec.EXACTLY) {
            setMeasuredDimension(width + pl + pr, heightMeasureSize);
        } else if (widthMeasureMode == MeasureSpec.EXACTLY && heightMeasureMode == MeasureSpec.EXACTLY) {
            setMeasuredDimension(widthMeasureSize, heightMeasureSize);
        } else if (widthMeasureMode == MeasureSpec.EXACTLY && heightMeasureMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(widthMeasureSize, height + pd + pt);
        }
    }

    public void setImageBitmap(Bitmap bitmap) {
        recycleBitmap();
        this.mBitmap = bitmap;
        squareBitmap();
        invalidate();
    }

    public void setImageDrawable(Drawable drawable) {
        setImageBitmap(drawable == null ? null : drawableToBitmap(drawable));
    }

    public void setImageResource(int resId) {
        setImageDrawable(ContextCompat.getDrawable(mContext, resId));
    }

    public void setLineColorResource(int resId) {
        setLineColor(ContextCompat.getColor(mContext, resId));
    }

    public void setLineColor(int color) {
        mLineColor = color;
        invalidate();
    }

    /**
     * 设置线的宽度
     *
     * @param width 这个宽度的单位是px
     */
    public void setLineWidth(int width) {
        mLineWidth = width;
        invalidate();
    }

    private Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();
        } else if (drawable instanceof NinePatchDrawable) {
            // 取 drawable 的长宽
            int w = drawable.getIntrinsicWidth();
            int h = drawable.getIntrinsicHeight();

            // 取 drawable 的颜色格式
            Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
                    : Bitmap.Config.RGB_565;
            // 建立对应 bitmap
            Bitmap bitmap = Bitmap.createBitmap(w, h, config);

            // 建立对应 bitmap 的画布
            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, w, h);
            // 把 drawable 内容画到画布中
            drawable.draw(canvas);

            return bitmap;
        } else {
            return null;
        }
    }


    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        recycleBitmap();
    }

    /**
     * 释放图片资源
     */
    private void recycleBitmap() {
        if (mBitmap != null) {
            mBitmap.recycle();
            mBitmap = null;
        }
    }
}

上面就是自定义View的全部代码了,代码的关键位置都写了注释,同时也很简单,相信大家一看就懂了,所以不多做解释。本自定义圆形ImageView为了方便在布局中设置图片、边框颜色和边框宽度,在attrs.xml 文件中添加了以下属性:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CircleImageView">
        <attr name="src" format="reference"></attr>
        <attr name="line_color" format="color"></attr>
        <attr name="line_width" format="dimension"></attr>
    </declare-styleable>
</resources>

同时在初始化控件的时候获取了设置的属性:

       TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);
        BitmapDrawable drawable = (BitmapDrawable) ta.getDrawable(R.styleable.CircleImageView_src);
        if (drawable != null)
            mBitmap = drawable.getBitmap();
        mLineColor = ta.getColor(R.styleable.CircleImageView_line_color, Color.WHITE);
        mLineWidth = (int) ta.getDimension(R.styleable.CircleImageView_line_width, 0);
        ta.recycle();

这里需要注意在使用完TypedArray 之后,需要及时的调用ta.recycle()释放资源。

以上就是自定义圆形ImageView的所有代码和说明了,大家有不懂的欢迎留言。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值