Android绘制圆形ImageView的几种实现方法

圆形Imagview有几种方法,这里我列举两种方法出来仅供大家参考,当然还有其它的几种方法,我就不一一赘述了



1.重写onDraw(Canvas canvas)通过Canvas来画圆,传入带bitmapShaper的画笔

public class CircleImageView extends ImageView {


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

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


    private void init(){
        //创建画笔
        paint = new Paint();
        paint.setAntiAlias(true); // 防止边缘的锯齿
        paint.setColor(Color.WHITE); // 这里的颜色决定了边缘的颜色

        mShaderMatrix=new Matrix();

    }
    /**
     * 位图对象
     * */
    private Bitmap mbitmap;
    Paint paint;

    protected void onDraw(Canvas canvas) {
        Drawable drawable = getDrawable();
        if (drawable == null) {
            return;
        }
        if (getWidth() == 0 || getHeight() == 0) {
            return;
        }
        if(mbitmap==null){
            mbitmap=DrawableToBitmap(drawable);
           setBitmapsharder();
        }
       if(mbitmap==null)
        return;

        int radius=getWidth()> getHeight()?getHeight()/2:getWidth()/2;
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, paint);
    }

    BitmapShader mBitmapShader=null;
    private void setBitmapsharder(){
        if (mbitmap!=null&&paint!=null&&width!=0&&height!=0){
            mBitmapShader=new BitmapShader(mbitmap, Shader.TileMode.CLAMP,Shader.TileMode.CLAMP);
            paint.setShader(mBitmapShader);

            float scale=0;

            mBitmapHeight = mbitmap.getHeight();
            mBitmapWidth = mbitmap.getWidth();
            mShaderMatrix.set(null);

            if (width>height) {
                if(mBitmapWidth>mBitmapHeight)
                    scale=((float)height)/mBitmapHeight;
                else
                    scale=((float)height)/mBitmapWidth;
            } else {
                if(mBitmapWidth>mBitmapHeight)
                    scale=((float)width)/mBitmapHeight;
                else
                    scale=((float)width)/mBitmapWidth;
            }
            //设置图片缩放
            mShaderMatrix.setScale(scale, scale);
           //设置图片平移显示
            if(mBitmapWidth>mBitmapHeight){
                mShaderMatrix.postTranslate(-(mBitmapWidth-mBitmapHeight)*scale/2,0);
            }else{
                mShaderMatrix.postTranslate(0,-(mBitmapHeight-mBitmapWidth)*scale/2);
            }
            mBitmapShader.setLocalMatrix(mShaderMatrix);

        }
    }
    Matrix mShaderMatrix;
    private int mBitmapWidth;
    private int mBitmapHeight;
    private int height;
    private int width;

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        height=getHeight();
        width=getWidth();
        setBitmapsharder();
    }


    @Override
    public void setImageBitmap(Bitmap bm) {
        super.setImageBitmap(bm);
        mbitmap=bm;
        setBitmapsharder();
    }
    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        mbitmap=DrawableToBitmap(drawable);
        setBitmapsharder();

    }

    @Override
    public void setImageResource(int resId) {
        super.setImageResource(resId);
        mbitmap=DrawableToBitmap(getContext(),resId);
        setBitmapsharder();
    }
    @Override
    public void setImageURI(Uri uri) {
        super.setImageURI(uri);
        mbitmap=DrawableToBitmap(getDrawable());
        setBitmapsharder();
    }

    /**
     * Drawable转换为Bitmap
     * */
    public static  Bitmap DrawableToBitmap(Drawable drawable){
        if(drawable==null)
            return null;
        if(drawable instanceof  BitmapDrawable)
            return ((BitmapDrawable)drawable).getBitmap();

        Bitmap bitmap=null;
        //如果是ColorDrawable随便给一个宽高
        if(drawable instanceof  ColorDrawable)
            bitmap=Bitmap.createBitmap(2,2,Bitmap.Config.ARGB_8888);
        else
        bitmap=Bitmap.createBitmap(drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight(),Bitmap.Config.ARGB_8888);

        Canvas canvas=new Canvas(bitmap);
        //设置绘制的矩形区域
        drawable.setBounds(0,0,drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight());
        drawable.draw(canvas);
        return bitmap;
    }
    /**
     * Drawable转换为Bitmap
     * */
    public static  Bitmap DrawableToBitmap(Context mContext,int ResId){
        Bitmap bitmap= BitmapFactory.decodeResource(mContext.getResources(),ResId);
        return bitmap;
    }


}

这里的有几个核心的点有

第一个就是ondraw里面画圆,注意圆心的坐标以及圆的半径(半径为最小)

第二点通过setBitmapSharder方法,里面t通过Martix设置位图的缩放比例以及位图的偏移量

关于Martix的操作

Matrix的操作,总共分为translate(平移),rotate(旋转),scale(缩放)和skew(倾斜)四种,每一种变换在 Android的API里都提供了set, post和pre三种操作方式,除了translate,其他三种操作都可以指定中心点。

set是直接设置Matrix的值,每次set一次,整个Matrix的数组都会变掉。

post是后乘,当前的矩阵乘以参数给出的矩阵。可以连续多次使用post,来完成所需的整个变换。

具体怎么用的可以去参考一下片文章Android Matrix详解






2.通过绘制圆形的Bitmap,绘制Imagvivew

public class CircleImageView extends ImageView {


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

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

    private void init(){

        mScaleType=getScaleType();
        //创建画笔
        paint = new Paint();
        paint.setAntiAlias(true); // 防止边缘的锯齿
        paint.setColor(Color.BLACK); // 这里的颜色决定了边缘的颜色
    }
    /**
     * 位图对象
     * */
    private Bitmap mbitmap;
    Paint paint;
    private Rect rect=new Rect();

    ScaleType mScaleType;
    protected void onDraw(Canvas canvas) {
        Drawable drawable = getDrawable();
        if (drawable == null) {
            return;
        }
        if (getWidth() == 0 || getHeight() == 0) {
            return;
        }
        if(mbitmap==null){
            mbitmap=DrawableToBitmap(drawable);
        }
       if(mbitmap==null)
        return;

        int radius=getWidth()> getHeight()?getHeight()/2:getWidth()/2;
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, paint);
        //把圆形bitmap居中对齐
        canvas.drawBitmap(drawCircleBitmap(mbitmap, radius),  getWidth() / 2-radius,getHeight() / 2-radius, paint);
    }

    /*
    *画圆形的bitmap
    *
     */
    public static Bitmap drawCircleBitmap(Bitmap bmp, int radius){
        if (bmp.getWidth() != radius || bmp.getHeight() != radius){
            /**
             * 把图片进行缩放,以宽高最小的一方为准,缩放图片比例
             * */
           double diameter=radius*2;//获取直径
          
            if(bmp.getWidth()> bmp.getHeight()){
                bmp = Bitmap.createScaledBitmap(bmp, (int)( diameter*bmp.getWidth()/bmp.getHeight()),  (int)diameter, false);
            }else  if(bmp.getWidth()< bmp.getHeight()){
                bmp = Bitmap.createScaledBitmap(bmp,  (int)(diameter/bmp.getWidth()*bmp.getHeight()), (int) diameter, false);
            }else{
                bmp = Bitmap.createScaledBitmap(bmp,  (int)diameter,  (int)diameter, false);
            }
        }
        Bitmap output = Bitmap.createBitmap(radius*2, radius*2, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        //设置画笔全透明
        canvas.drawARGB(0, 0, 0, 0);
        Paint paints = new Paint();
        paints.setColor(Color.WHITE);
        paints.setAntiAlias(true);//去锯齿
        paints.setFilterBitmap(true);
        //防抖动
        paints.setDither(true);

        //把图片圆形绘制在面部中心
        canvas.drawCircle(radius, radius, radius, paints);

        // 取两层绘制交集。显示前景色。
        paints.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        Rect rect=new Rect();
        if(bmp.getWidth()>=bmp.getHeight()){
            rect.set(bmp.getWidth()/2-radius,0,bmp.getWidth()/2+radius,radius*2);
        }else{
            rect.set(0,bmp.getHeight()/2-radius,radius*2,bmp.getHeight()/2+radius);
        }
        Rect rect2=new Rect(0,0,radius*2,radius*2);
        //第一个rect 针对bmp的绘制区域,rect2表示绘制到上面位置
        canvas.drawBitmap(bmp, rect, rect2, paints);
        bmp.recycle();
        return output;
    }

    /**
     * 设置显示类型
     * */
    @Override
    public void setScaleType(ScaleType scaleType) {
        super.setScaleType(scaleType);
        mScaleType=scaleType;
    }

    @Override
    public void setImageBitmap(Bitmap bm) {
        super.setImageBitmap(bm);
        mbitmap=bm;
    }
    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        mbitmap=DrawableToBitmap(drawable);
    }

    @Override
    public void setImageResource(int resId) {
        super.setImageResource(resId);
        mbitmap=DrawableToBitmap(getContext(),resId);
    }
    @Override
    public void setImageURI(Uri uri) {
        super.setImageURI(uri);
        mbitmap=DrawableToBitmap(getDrawable());
    }





    /**
     * Drawable转换为Bitmap
     * */
    public static  Bitmap DrawableToBitmap(Drawable drawable){
        if(drawable==null)
            return null;
        if(drawable instanceof  BitmapDrawable)
            return ((BitmapDrawable)drawable).getBitmap();

        Bitmap bitmap=null;
        //如果是ColorDrawable随便给一个宽高
        if(drawable instanceof  ColorDrawable)
            bitmap=Bitmap.createBitmap(2,2,Bitmap.Config.ARGB_8888);
        else
        bitmap=Bitmap.createBitmap(drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight(),Bitmap.Config.ARGB_8888);

        Canvas canvas=new Canvas(bitmap);
        //设置绘制的矩形区域
        drawable.setBounds(0,0,drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight());
        drawable.draw(canvas);
        return bitmap;
    }
    /**
     * Drawable转换为Bitmap
     * */
    public static  Bitmap DrawableToBitmap(Context mContext,int ResId){
        Bitmap bitmap= BitmapFactory.decodeResource(mContext.getResources(),ResId);
        return bitmap;
    }

}

这个中绘制方法更简单我觉得可以不用重新Imagview就可以实现,把 drawCircleBitmap方法就行封装一下得到圆形的bitmap然后在设置给Imageveiw就可以实现了绘制好之后记得把之前的的bitmap给reclye了

这里画圆形view使用是在画布上面画一个圆,然后把bitmap也画上去,然后去交叉前景图

具体paint.setXfermode(newPorterDuffXfermode(PorterDuff.Mode.SRC_IN))

这里面的几种交叉取景可以参考Android Paint之 setXfermode PorterDuffXfermode 讲解这篇文字



3.还要其他的几种方式,比如画一个中间透明的圆形遮盖在上面等等



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值