自定义圆形或者圆角矩形图片

学习资源:http://blog.csdn.net/lmj623565791/article/details/24555655

好了 ,以前对圆角图片一致觉得不解。到底是怎么做的啊,好高端啊。废话不多说了。先上代码

1 自定义属性集:

 <attr name="borderRadius" format="dimension"></attr>
    <attr name="type">
        <enum name="circle" value="0"></enum>
        <enum name="round" value="1"></enum>
    </attr>
    <attr name="src" format="reference"></attr>

    <declare-styleable name="CustomImageView">
        <attr name="borderRadius"></attr>
        <attr name="type"></attr>
        <attr name="src"></attr>
    </declare-styleable>

以前对自定义属性集很是不解,为什么这个属性集都没有值,只有属性有毛用?今天才恍然大悟。先往后看吧。

2.自定义控件


    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) {
        this(context,null);
    }

    public CustomImageView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    /**
     * 初始化自定义参数
     *
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    public CustomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomImageView, defStyleAttr, 0);
        int n = array.getIndexCount();
        for (int i = 0; i < n; i++) {
            int attr = array.getIndex(i);
            switch (attr) {
                case R.styleable.CustomImageView_src:
                    mSrc = BitmapFactory.decodeResource(getResources(),array.getResourceId(attr,0));
                    break;
                case R.styleable.CustomImageView_borderRadius:
                    mRadius = array.getDimensionPixelSize(attr, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10f,getResources().getDisplayMetrics()));
                    break;
                case R.styleable.CustomImageView_type:
                    type = array.getInt(attr,0);
                    break;
            }
        }

        array.recycle();
    }


    /**
     * 计算控件的宽度和高度
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @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){
            mWidth = specSize;
        }else{
            int desireByImg = getPaddingLeft()+mSrc.getWidth()+getPaddingRight();
            if(specMode==MeasureSpec.AT_MOST){
                mWidth = Math.min(desireByImg,specSize);
            }else{
                mWidth = desireByImg;
            }
        }

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

        if(specMode==MeasureSpec.EXACTLY){
            mHeight = specSize;
        }else{
            int desireByImg = getPaddingTop()+mSrc.getHeight()+getPaddingBottom();
            if(specMode==MeasureSpec.AT_MOST){
                mHeight = Math.min(desireByImg,specSize);
            }else{
                mHeight = desireByImg;
            }
        }
    }

    /**
     * 绘制
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        switch (type){
            case TYPE_CIRCLE:
                int min = Math.min(mWidth,mHeight);
                /**
                 * 如果长度不一致 按小的进行压缩
                 */
                mSrc = Bitmap.createScaledBitmap(mSrc,mWidth,mHeight,false);
                canvas.drawBitmap(createCircleImage(mSrc,min),0,0,null);
                break;
            case TYPE_ROUND:
                canvas.drawBitmap(createRoundCornerBitmap(mSrc),0,0,null);
                break;
        }
    }

    /**
     * 根据原图和变长绘制圆形
     */
    private Bitmap createCircleImage(Bitmap source,int min){
        Paint paint = new Paint();
        paint.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,paint);
        /**
         * 使用SRC_IN
         */
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

        /**
         * 绘制图片
         */
        canvas.drawBitmap(source,0,0,paint);
        return target;
    }

    private Bitmap createRoundCornerBitmap(Bitmap source){
        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        Bitmap target = Bitmap.createBitmap(mWidth,mHeight, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(target);
        RectF rect = new RectF(0,0,source.getWidth(),source.getHeight());
        canvas.drawRoundRect(rect,mRadius,mRadius,paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(source,0,0,paint);
        return target;
    }

上面先整体把代码贴出来,接下来在解释。

!构造方法最终会调用第三个构造方法,这个以前还是没有用到过的。

 public CustomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomImageView, defStyleAttr, 0);
        int n = array.getIndexCount();
        for (int i = 0; i < n; i++) {
            int attr = array.getIndex(i);
            switch (attr) {
                case R.styleable.CustomImageView_src:
                    mSrc = BitmapFactory.decodeResource(getResources(),array.getResourceId(attr,0));
                    break;
                case R.styleable.CustomImageView_borderRadius:
                    mRadius = array.getDimensionPixelSize(attr, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10f,getResources().getDisplayMetrics()));
                    break;
                case R.styleable.CustomImageView_type:
                    type = array.getInt(attr,0);
                    break;
            }
        }

        array.recycle();
    }

在此构造方法中首先是获取所有的属性集合

 TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomImageView, defStyleAttr, 0);

然后遍历属性集合中的属性

 for (int i = 0; i < n; i++) {
            int attr = array.getIndex(i);
            switch (attr) {
                case R.styleable.CustomImageView_src:
                    mSrc = BitmapFactory.decodeResource(getResources(),array.getResourceId(attr,0));
                    break;
                case R.styleable.CustomImageView_borderRadius:
                    mRadius = array.getDimensionPixelSize(attr, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10f,getResources().getDisplayMetrics()));
                    break;
                case R.styleable.CustomImageView_type:
                    type = array.getInt(attr,0);
                    break;
            }
        }

注意这里只是把属性值取出来,真正的赋值操作在这里

<com.bbdtek.circle_imageview.CustomImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        customview:src="@mipmap/icon"
        customview:type="circle"
        customview:borderRadius="50dp"/>

额,这个我感觉还是很好用的,以前真没有这么用过。别忘了引入自定义的命名空间。

 xmlns:customview="http://schemas.android.com/apk/res-auto"

这里的res-auto听说是在studio中才是这么用,如果是eclipse就要写成全类名。

好吧,我这里只是重点说一下这个属性集合,以前没有用过。关于圆形的onMeasure 和onDraw方法就不多说了。主要还是一句代码

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

这句代码的意思就是要去bitmap和圆形的交集的部分 关于Mode的更多属性,参考下图
这里写图片描述

有一点比较迷惑的就是我自定义的控件里写的明明是wrap_content ,但是这个空间为什么会充满屏幕。好奇怪。我这里背景色写成红色是为了容易看出控件的大小。
这里写图片描述

这个是运行效果:
这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值