Android自定义圆形圆角图片示例

本文参考自大神张鸿洋的文章,同时修复了一个我自己发现的问题(因为不知道算不算Bug):当显示圆形图片时,若在xml中设置的图片的宽高属性为wrap_content,而所用的图片宽高比不为1。当width>height时,图片只显示从左边开始长度为height值的部分;当height>width时,图片只显示从上边开始高度为width值的部分;所以我做了一点处理,使其达到类似于 android:scaleType=”center”的功能。

图片显示效果

demo地址为:Android自定义圆形圆角图片示例

这里只贴自定义View代码如下:

package com.android.circularpicture;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.ImageView;

/**
 * 自定义圆形ImageView
 * 作者: k.k on 2017/8/29.
 * 邮箱:214525789@qq.com
 */

public class CircularImageView extends ImageView {

    //图片类型(circle/round)
    private int type;

    private Bitmap mImg;//图片

    private int mWidth;//控件的宽度

    private int mHeight;//控件的高度

    private int mRadius;//圆角的半径

    private Bitmap circleView;//加载的圆形View

    private Bitmap roundView;//加载的圆角View

    /*这个构造方法必须要*/
    public CircularImageView(Context context) {
        this(context, null);
    }

    /*这个构造方法必须要*/
    public CircularImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    /*真正的执行在这里*/
    public CircularImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        TypedArray typedarray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CircularImageView, defStyle, 0);
        int counts = typedarray.getIndexCount();
        for (int i = 0; i < counts; i++) {
            int attr = typedarray.getIndex(i);
            switch (attr) {
                case R.styleable.CircularImageView_src:
                    mImg = BitmapFactory.decodeResource(getResources(), typedarray.getResourceId(attr, 0));
                    break;
                case R.styleable.CircularImageView_borderRadius:
                    int defValue = (int) TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_DIP, 10f, getResources().getDisplayMetrics()
                    );//applyDimension()是一个将各种单位的值转换为像素的方法,第一个参数是指第二个参数值得单位,并将该单位的值转换为px,在这里TypedValue.COMPLEX_UNIT_DIP表示dp,即10f表示10dp
                    mRadius = typedarray.getDimensionPixelSize(attr, defValue);
                    break;
                case R.styleable.CircularImageView_type:
                    type = typedarray.getInt(attr, 0);
                    break;
            }
        }
        typedarray.recycle();//记得回收掉
    }


    //重写onMeasure方法,计算控件的宽度和高度
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

         /*设置宽度*/
        int specMode = MeasureSpec.getMode(widthMeasureSpec);
        int specSize = MeasureSpec.getSize(widthMeasureSpec);

        //类型:match parent(继承父布局的值),accurate(精确的值)
        if (specMode == MeasureSpec.EXACTLY) {
            mWidth = specSize;//此时,控件的宽度即为specSize
        } else {
            //由控件自身决定宽度
            int demandWidthImg = getPaddingLeft() + getPaddingRight() + mImg.getWidth();

            //类型:wrap_parent
            if (specMode == MeasureSpec.AT_MOST) {
                mWidth = Math.min(demandWidthImg, specSize);//返回较小的那个数值
            }
            //这种情况很少使用到
            else {
                mWidth = specSize;
            }
        }

        /*设置高度*/
        specMode = MeasureSpec.getMode(heightMeasureSpec);
        specSize = MeasureSpec.getSize(heightMeasureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            mHeight = specSize;
        } else {
            int demandHeightImg = getPaddingTop() + getPaddingBottom() + mImg.getHeight();

            if (specMode == MeasureSpec.AT_MOST) {
                mHeight = Math.min(demandHeightImg, specSize);
            } else {
                mHeight = specSize;
            }
        }

        setMeasuredDimension(mWidth, mHeight);//设置View宽高的值(实际叫测量值)
    }


    /*重写onDraw方法,绘制对应的图片*/
    @Override
    protected void onDraw(Canvas canvas) {
        float horizontalOffset = mWidth > mHeight ? (mWidth - mHeight) / 2 : (mHeight - mWidth) / 2;//需要调整的偏移量
        switch (type) {
            //绘制圆形图片
            case Constant.CIRCLE_TYPE:
                int diameter = Math.min(mWidth, mHeight);//因为是绘制圆形图片,如果mWidth,mHeight不一致,取小的值作为圆图的直径
                mImg = Bitmap.createScaledBitmap(mImg, diameter, diameter, false);//以w,h为目标对bitmap进行缩放,filter表示是否要对位图进行过滤(滤波)处理这个方法的效果就类似于ImageView.ScaleType.FIT_XY
                if (mWidth > mHeight) {
                    canvas.drawBitmap(createCircleView(mImg, diameter), horizontalOffset, 0, null);
                } else {
                    canvas.drawBitmap(createCircleView(mImg, diameter), 0, horizontalOffset, null);
                }
                circleView = null;
                break;
            //绘制带圆角的图片
            case Constant.ROUND_TYPE:
                canvas.drawBitmap(createRoundView(mImg), 0, 0, null);
                roundView = null;
                break;
        }
    }

    /*绘制圆形View*/
    private Bitmap createCircleView(Bitmap bitmap, int diameter) {
        Paint paint = new Paint();
        paint.setAntiAlias(true);//设置抗锯齿方法
        circleView = Bitmap.createBitmap(diameter, diameter, Bitmap.Config.ARGB_8888);

        Canvas canvas = new Canvas(circleView);//产生一个同样大小的画布

        canvas.drawCircle(diameter / 2, diameter / 2, diameter / 2, paint);//绘制圆形

        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

        canvas.drawBitmap(bitmap, 0, 0, paint);

        return circleView;
    }

    /*绘制圆角View*/
    private Bitmap createRoundView(Bitmap bitmap) {
        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        roundView = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);

        Canvas canvas = new Canvas(roundView);

        RectF rect = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());

        canvas.drawRoundRect(rect, mRadius, mRadius, paint);

        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

        canvas.drawBitmap(bitmap, 0, 0, paint);

        return roundView;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值