Android自定义View圆形头像

在很多的开发中经常会用到圆形头像来显示一些信息,通常情况下会直接使用第三方依赖库来快速的去实现功能。没有研究其内部原理,其实内部实现很简单。

效果图如下:图片尺寸自动根据控件尺寸进行缩放或放大,自定义边框的宽度和颜色

步骤实现

  1. 缩放图片让其宽高根据view进行设置

  1. 先将目标图片绘制在画布上

  1. 绘制一个圆形,将两个画布进行重叠。使用DST_IN重叠模式

  1. 添加自定义属性 如边框和边框的颜色

这里我们直接继承ImageView,可以省去onLayout、onMeasure操作。重写onLayout()根据getDrawable()获取到设置的图片资源

    BitmapDrawable bitmapDrawable = (BitmapDrawable) getDrawable();
    mBitmap = bitmapDrawable.getBitmap();

先根据控件的大小来设置bitmap的大小,使用Matrix矩阵来进行设置

 int bitmapWidth = mBitmap.getWidth();
 int bitmapHeight = mBitmap.getHeight();

 int viewWidth = getWidth();
 int viewHeight = getHeight();

 //计算缩放的比例
 float scaleW = viewWidth / (float)bitmapWidth;
 float scaleH = viewHeight / (float)bitmapHeight;
 //用来缩放的矩阵
 Matrix matrix = new Matrix();
 matrix.reset();
 matrix.setScale(scaleW,scaleH);
 mScaledBitmap = Bitmap.createBitmap(mBitmap,0,0
        ,bitmapWidth,bitmapHeight
        ,matrix,true);

重写onDraw方法,如果当前bitmap不为空的情况下自己处理绘制,为空则交给系统处理

 @Override
    protected void onDraw(Canvas canvas) {
        if (mBitmap == null) {
            super.onDraw(canvas);
        } else {
            onDrawCircleView(canvas);
        }

    }

绘制圆形遮罩层

Bitmap.Config config = Bitmap.Config.ARGB_8888;
bitmapMask = Bitmap .createBitmap(getWidth(),getHeight(),config);
Canvas canvas = new Canvas(bitmapMask);
canvas.drawOval(0,0,getWidth(),getHeight(),mPaint);

将资源绘制到画布上,因为涉及到绘制重叠。需要对画布进行设置,需要对画布进行saveLayer操作如下图:将内容进行重叠

int saveLayer = canvas.saveLayer(0, 0, getWidth(), getHeight(), mPaint,Canvas.ALL_SAVE_FLAG);

//绘制目标图像
canvas.drawBitmap(mScaledBitmap,0 ,0, mPaint);
//设置画布重叠模式
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
//绘制遮罩
canvas.drawBitmap(bitmapMask,0,0,mPaint);
//清空画笔模式
mPaint.setXfermode(null);
canvas.restoreToCount(saveLayer);
//绘制边框
ondrawBorder(canvas);

最后绘制边框,根据自定义属性读取颜色和宽度属性

mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(strokeColor);
mPaint.setStrokeWidth(strokeWidth);
canvas.drawOval(strokeWidth/2, strokeWidth/2, getWidth() - strokeWidth/2, getHeight() - strokeWidth/2, mPaint);

绘制起来很简单,只要对需求进行拆分一步步去实现就能做出效果,有时候一个小小的变通就能节省很多事情。

以下是完整代码:

public class RoundImageView extends ImageView {

    Paint mPaint;
    Bitmap mBitmap;
    Bitmap bitmapMask;
    Bitmap mScaledBitmap;
    int strokeWidth = 3;
    int strokeColor = Color.WHITE;

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

    public RoundImageView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public RoundImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //获取自定义属性
        TypedArray typeface = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView);
        strokeWidth = typeface.getDimensionPixelOffset(R.styleable.RoundImageView_stroke_width,strokeWidth);
        strokeColor = typeface.getColor(R.styleable.RoundImageView_storke_color,strokeColor);
        typeface.recycle();

        init();
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mBitmap == null) {
            super.onDraw(canvas);
        } else {
            onDrawCircleView(canvas);
        }

    }

    private void onDrawCircleView(Canvas canvas) {
        int saveLayer = canvas.saveLayer(0, 0, getWidth(), getHeight(), mPaint,Canvas.ALL_SAVE_FLAG);

        //绘制目标图像
        canvas.drawBitmap(mScaledBitmap,0 ,0, mPaint);
        //设置画布重叠模式
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        //绘制遮罩
        canvas.drawBitmap(bitmapMask,0,0,mPaint);
        //清空画笔模式
        mPaint.setXfermode(null);

        canvas.restoreToCount(saveLayer);

        //绘制边框
       ondrawBorder(canvas);
    }

    private void ondrawBorder(Canvas canvas) {
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(strokeColor);
        mPaint.setStrokeWidth(strokeWidth);

        canvas.drawOval(strokeWidth/2, strokeWidth/2, getWidth() - strokeWidth/2, getHeight() - strokeWidth/2, mPaint);
    }

    private void createMask() {
        Bitmap.Config config = Bitmap.Config.ARGB_8888;
        bitmapMask = Bitmap .createBitmap(getWidth(),getHeight(),config);

        Canvas canvas = new Canvas(bitmapMask);
        canvas.drawOval(0,0,getWidth(),getHeight(),mPaint);
    }

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

        BitmapDrawable bitmapDrawable = (BitmapDrawable) getDrawable();
        mBitmap = bitmapDrawable.getBitmap();
        //缩放图片
        scaleBitmap();
        //绘制遮罩图像
        createMask();
    }

    /**
     * 按照控件大小缩放放大图片
     */
    private void scaleBitmap(){
        if(mScaledBitmap == null && mBitmap != null){
            int bitmapWidth = mBitmap.getWidth();
            int bitmapHeight = mBitmap.getHeight();

            int viewWidth = getWidth();
            int viewHeight = getHeight();

            //计算缩放的比例
            float scaleW = viewWidth / (float)bitmapWidth;
            float scaleH = viewHeight / (float)bitmapHeight;

            //用来缩放的矩阵
            Matrix matrix = new Matrix();
            matrix.reset();
            matrix.setScale(scaleW,scaleH);
            mScaledBitmap = Bitmap.createBitmap(mBitmap,0,0,bitmapWidth,bitmapHeight,matrix,true);
        }
    }
}

自定义属性:

    <declare-styleable name="RoundImageView">
        <attr name="stroke_width" format="dimension"/>
        <attr name="storke_color" format="color"/>
    </declare-styleable>

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值