您的位置:首页 > 移动开发 > Android开发

Android 完美实现图片圆角和圆形(对实现进行分析)

2014-07-22 11:16 477 查看
本来想在网上找个圆角的例子看一看,不尽人意啊,基本都是官方的Demo的那张原理图,稍后会贴出。于是自己自定义了个View,实现图片的圆角以及圆形效果。效果图:



第一个是原图,第二个是圆形效果,第三第四设置了不同的圆角大小。

准备改变一个博客的风格,首先给大家讲一下原理,让大家明白了,然后再贴代码,不然可以直接看那么长的代码也比较痛苦,核心代码其实就那么几行:

核心代码分析:

[java] view
plaincopy





/** 

     * 根据原图和变长绘制圆形图片 

     *  

     * @param source 

     * @param min 

     * @return 

     */  

    private Bitmap createCircleImage(Bitmap source, int min)  

    {  

        final Paint paint = new Paint();  

        paint.setAntiAlias(true);  

        Bitmap target = Bitmap.createBitmap(min, min, Config.ARGB_8888);  

        /** 

         * 产生一个同样大小的画布 

         */  

        Canvas canvas = new Canvas(target);  

        /** 

         * 首先绘制圆形 

         */  

        canvas.drawCircle(min / 2, min / 2, min / 2, paint);  

        /** 

         * 使用SRC_IN 

         */  

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

        /** 

         * 绘制图片 

         */  

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

        return target;  

    }  

其实主要靠:paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));这行代码,为什么呢,我给大家解释下,SRC_IN这种模式,两个绘制的效果叠加后取交集展现后图,怎么说呢,咱们第一个绘制的是个圆形,第二个绘制的是个Bitmap,于是交集为圆形,展现的是BItmap,就实现了圆形图片效果。圆角,其实就是先绘制圆角矩形,是不是很简单,以后别人再说实现圆角,你就把这一行代码给他就行了。

从Android的示例中,给大家证明一下:

下面有一张PorterDuff.Mode的16中效果图,咱们的只是其一:



源码咱们只关心谁先谁后绘制的:

[java] view
plaincopy





canvas.translate(x, y);  

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

              paint.setXfermode(sModes[i]);  

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

              paint.setXfermode(null);  

              canvas.restoreToCount(sc);  

可以看出先绘制的Dst,再绘制的Src,最后的展示是SrcIn那个图:显示的区域是二者交集,展示的是Src(后者)。和咱们前面结论一致。效果16种,大家可以自由组合展示不同的效果。

好了,原理和核心代码解释完成。下面开始写自定义View。

1、自定义属性:

[html] view
plaincopy





<?xml version="1.0" encoding="utf-8"?>  

<resources>  

  

    <attr name="borderRadius" format="dimension" />  

    <attr name="type">  

        <enum name="circle" value="0" />  

        <enum name="round" value="1" />  

    </attr>  

    <attr name="src" format="reference"></attr>  

  

    <declare-styleable name="CustomImageView">  

        <attr name="borderRadius" />  

        <attr name="type" />  

        <attr name="src" />  

    </declare-styleable>  

  

</resources>  

2、构造中获取自定义的属性:

[java] view
plaincopy





/** 

 * TYPE_CIRCLE / TYPE_ROUND 

 */  

private int type;  

private static final int TYPE_CIRCLE = 0;  

private static final int TYPE_ROUND = 1;  

  

/** 

 * 图片 

 */  

private Bitmap mSrc;  

  

/** 

 * 圆角的大小 

 */  

private int mRadius;  

  

/** 

 * 控件的宽度 

 */  

private int mWidth;  

/** 

 * 控件的高度 

 */  

private int mHeight;  

  

public CustomImageView(Context context, AttributeSet attrs)  

{  

    this(context, attrs, 0);  

}  

  

public CustomImageView(Context context)  

{  

    this(context, null);  

}  

  

/** 

 * 初始化一些自定义的参数 

 *  

 * @param context 

 * @param attrs 

 * @param defStyle 

 */  

public CustomImageView(Context context, AttributeSet attrs, int defStyle)  

{  

    super(context, attrs, defStyle);  

  

    TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomImageView, defStyle, 0);  

  

    int n = a.getIndexCount();  

    for (int i = 0; i < n; i++)  

    {  

        int attr = a.getIndex(i);  

        switch (attr)  

        {  

        case R.styleable.CustomImageView_src:  

            mSrc = BitmapFactory.decodeResource(getResources(), a.getResourceId(attr, 0));  

            break;  

        case R.styleable.CustomImageView_type:  

            type = a.getInt(attr, 0);// 默认为Circle  

            break;  

        case R.styleable.CustomImageView_borderRadius:  

            type = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10f,  

                    getResources().getDisplayMetrics()));// 默认为10DP  

            break;  

        }  

    }  

    a.recycle();  

}  

3、onMeasure中获取控件宽高:

[java] view
plaincopy





/** 

     * 计算控件的高度和宽度 

     */  

    @Override  

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  

    {  

        // super.onMeasure(widthMeasureSpec, heightMeasureSpec);  

  

        /** 

         * 设置宽度 

         */  

        int specMode = MeasureSpec.getMode(widthMeasureSpec);  

        int specSize = MeasureSpec.getSize(widthMeasureSpec);  

  

        if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate  

        {  

            mWidth = specSize;  

        } else  

        {  

            // 由图片决定的宽  

            int desireByImg = getPaddingLeft() + getPaddingRight() + mSrc.getWidth();  

            if (specMode == MeasureSpec.AT_MOST)// wrap_content  

            {  

                mWidth = Math.min(desireByImg, specSize);  

            }  

        }  

  

        /*** 

         * 设置高度 

         */  

  

        specMode = MeasureSpec.getMode(heightMeasureSpec);  

        specSize = MeasureSpec.getSize(heightMeasureSpec);  

        if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate  

        {  

            mHeight = specSize;  

        } else  

        {  

            int desire = getPaddingTop() + getPaddingBottom() + mSrc.getHeight();  

            if (specMode == MeasureSpec.AT_MOST)// wrap_content  

            {  

                mHeight = Math.min(desire, specSize);  

            }  

        }  

        setMeasuredDimension(mWidth, mHeight);  

  

    }  

4、根据Type绘制:

[java] view
plaincopy





/** 

     * 绘制 

     */  

    @Override  

    protected void onDraw(Canvas canvas)  

    {  

  

        switch (type)  

        {  

        // 如果是TYPE_CIRCLE绘制圆形  

        case TYPE_CIRCLE:  

  

            int min = Math.min(mWidth, mHeight);  

            /** 

             * 长度如果不一致,按小的值进行压缩 

             */  

            mSrc = Bitmap.createScaledBitmap(mSrc, min, min, false);  

  

            canvas.drawBitmap(createCircleImage(mSrc, min), 0, 0, null);  

            break;  

        case TYPE_ROUND:  

            canvas.drawBitmap(createRoundConerImage(mSrc), 0, 0, null);  

            break;  

  

        }  

  

    }  

  

    /** 

     * 根据原图和变长绘制圆形图片 

     *  

     * @param source 

     * @param min 

     * @return 

     */  

    private Bitmap createCircleImage(Bitmap source, int min)  

    {  

        final Paint paint = new Paint();  

        paint.setAntiAlias(true);  

        Bitmap target = Bitmap.createBitmap(min, min, Config.ARGB_8888);  

        /** 

         * 产生一个同样大小的画布 

         */  

        Canvas canvas = new Canvas(target);  

        /** 

         * 首先绘制圆形 

         */  

        canvas.drawCircle(min / 2, min / 2, min / 2, paint);  

        /** 

         * 使用SRC_IN,参考上面的说明 

         */  

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

        /** 

         * 绘制图片 

         */ 

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

        return target;  

    }  

  

    /** 

     * 根据原图添加圆角 

     *  

     * @param source 

     * @return 

     */  

    private Bitmap createRoundConerImage(Bitmap source)  

    {  

        final Paint paint = new Paint();  

        paint.setAntiAlias(true);  

        Bitmap target = Bitmap.createBitmap(mWidth, mHeight, Config.ARGB_8888);  

        Canvas canvas = new Canvas(target);  

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

        canvas.drawRoundRect(rect, 50f, 50f, paint);  

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

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

        return target;  

    }  

转自:http://blog.csdn.net/lmj623565791/article/details/24555655
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 圆角图片