这才是真正的万能圆角ImageView

标签: imageview
559人阅读 评论(0) 收藏 举报
分类:

本文已授权我的公众号:我就是马云飞 独家发布

不知道有没有人记得我去年写过一个圆角的imageview。不知道的可以先去看看:万能圆角imagview,本文是基于上一篇的内容进行添加以及修改的。不然直接看这篇可能会有点懵。

前言

我为什么要二次封装?最近公司有个需求是这样的。
这里写图片描述

同事说,不知道怎么搞,于是乎,我把之前写的imageview给过去了。他来了句,你这圆角和fitxy同时设置会有问题啊,我反手就是一个大嘴巴子。我的代码怎么会有问题。于是,拿来一瞧,的确有点问题。So,我决定对这个imageview进行二次的封装。(当然了,这个问题的最后处理是后台直接给一个圆角的imageview)。

如何实现

细想一下,上文我们是怎么做的,我们是把绘制的区域,从(0,0)移动到我们想要的地方,说个粗暴点的话,我们强制的把这个imagview的scaletype的属性设置了centercrop。那么这次我们就要将它的scaletype设置成可调的属性。

实现逻辑

我前面也说过了,上次我们是根据imageview的源码来修改他的编辑区域的,这次,我们照常打开源码,找到园中对scaletype的处理逻辑,代码如下:


    private void configureBounds() {
        if (mDrawable == null || !mHaveFrame) {
            return;
        }

        final int dwidth = mDrawableWidth;
        final int dheight = mDrawableHeight;

        final int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
        final int vheight = getHeight() - mPaddingTop - mPaddingBottom;

        final boolean fits = (dwidth < 0 || vwidth == dwidth)
                && (dheight < 0 || vheight == dheight);

        if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
            /* If the drawable has no intrinsic size, or we're told to
                scaletofit, then we just fill our entire view.
            */
            mDrawable.setBounds(0, 0, vwidth, vheight);
            mDrawMatrix = null;
        } else {
            // We need to do the scaling ourself, so have the drawable
            // use its native size.
            mDrawable.setBounds(0, 0, dwidth, dheight);

            if (ScaleType.MATRIX == mScaleType) {
                // Use the specified matrix as-is.
                if (mMatrix.isIdentity()) {
                    mDrawMatrix = null;
                } else {
                    mDrawMatrix = mMatrix;
                }
            } else if (fits) {
                // The bitmap fits exactly, no transform needed.
                mDrawMatrix = null;
            } else if (ScaleType.CENTER == mScaleType) {
                // Center bitmap in view, no scaling.
                mDrawMatrix = mMatrix;
                mDrawMatrix.setTranslate(Math.round((vwidth - dwidth) * 0.5f),
                                         Math.round((vheight - dheight) * 0.5f));
            } else if (ScaleType.CENTER_CROP == mScaleType) {
                mDrawMatrix = mMatrix;

                float scale;
                float dx = 0, dy = 0;

                if (dwidth * vheight > vwidth * dheight) {
                    scale = (float) vheight / (float) dheight;
                    dx = (vwidth - dwidth * scale) * 0.5f;
                } else {
                    scale = (float) vwidth / (float) dwidth;
                    dy = (vheight - dheight * scale) * 0.5f;
                }

                mDrawMatrix.setScale(scale, scale);
                mDrawMatrix.postTranslate(Math.round(dx), Math.round(dy));
            } else if (ScaleType.CENTER_INSIDE == mScaleType) {
                mDrawMatrix = mMatrix;
                float scale;
                float dx;
                float dy;

                if (dwidth <= vwidth && dheight <= vheight) {
                    scale = 1.0f;
                } else {
                    scale = Math.min((float) vwidth / (float) dwidth,
                            (float) vheight / (float) dheight);
                }

                dx = Math.round((vwidth - dwidth * scale) * 0.5f);
                dy = Math.round((vheight - dheight * scale) * 0.5f);

                mDrawMatrix.setScale(scale, scale);
                mDrawMatrix.postTranslate(dx, dy);
            } else {
                // Generate the required transform.
                mTempSrc.set(0, 0, dwidth, dheight);
                mTempDst.set(0, 0, vwidth, vheight);

                mDrawMatrix = mMatrix;
                mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
            }
        }
    }

我们找到上次对其实位置修改的地方。跟着源码一样改成一样。改完之后代码如下:


        if (drawablewidth <= 0 || drawableheight <= 0) {
            drawable.setBounds(0, 0, viewwidth, viewheight);
            matrix = null;
        } else {
            drawable.setBounds(0, 0, drawablewidth, drawableheight);
            if (ScaleType.MATRIX == getScaleType()) {
                if (matrix.isIdentity()) {
                    matrix = null;
                }
            } else if (fits) {
                matrix = null;
            } else if (ScaleType.CENTER == getScaleType()) {
                matrix.setTranslate(Math.round((viewwidth - drawablewidth) * 0.5f),
                        Math.round((viewheight - drawableheight) * 0.5f));
            } else if (ScaleType.CENTER_CROP == getScaleType()) {
                if (drawablewidth * viewheight > viewwidth * drawableheight) {
                    dx = (viewwidth - drawablewidth * scale) * 0.5f;
                } else {
                    dy = (viewheight - drawableheight * scale) * 0.5f;
                }
                matrix.setScale(scale, scale);
                matrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
            } else if (ScaleType.CENTER_INSIDE == getScaleType()) {

                if (drawablewidth <= viewwidth && drawableheight <= viewheight) {
                    scale = 1.0f;
                } else {
                    scale = Math.min((float) viewwidth / (float) drawablewidth,
                            (float) viewheight / (float) drawableheight);
                }
                dx = Math.round((viewwidth - drawablewidth * scale) * 0.5f);
                dy = Math.round((viewheight - drawableheight * scale) * 0.5f);
                matrix.setScale(scale, scale);
                matrix.postTranslate(dx, dy);
            } else {
                if (drawablewidth * viewheight > viewwidth * drawableheight) {
                    dx = (viewwidth - drawablewidth * scale) * 0.5f;
                } else {
                    dy = (viewheight - drawableheight * scale) * 0.5f;
                }
                matrix.setScale(scale, scale);
                matrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
            }
        }
        if (ScaleType.FIT_XY == getScaleType() && matrix != null) {
            scale1 = viewwidth * 1.0f / drawablewidth;
            scale2 = viewheight * 1.0f / drawableheight;
            matrix.setScale(scale1, scale2);
        }
        bitmapShader.setLocalMatrix(matrix);
        paint.setShader(bitmapShader);

我们可以发现其实和源码对比下来,改动还是有的。为什么呢?我们仔细看下这段代码:

     if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
            /* If the drawable has no intrinsic size, or we're told to
                scaletofit, then we just fill our entire view.
            */
            mDrawable.setBounds(0, 0, vwidth, vheight);
            mDrawMatrix = null;
        }

源码里面只对drawable进行了处理。但我们可以发现后面的判断每次都会调用matrix.setScale这个方法。但在当scaletype为fitxy时,没有进行处理。我们也知道,我们看的是源码,他肯定偷偷的在某个地方进行了处理。那么我们要处理怎么办呢?仔细看代码:

        if (ScaleType.FIT_XY == getScaleType() && matrix != null) {
            scale1 = viewwidth * 1.0f / drawablewidth;
            scale2 = viewheight * 1.0f / drawableheight;
            matrix.setScale(scale1, scale2);
    }

fitxy我们都知道是充满布局,然后在细看这块代码,你是不是懂了呢?布局的宽高除以图片的宽高。然后设置它的比例。

加上边框

为了更好的封装,我选择加上边框和边框颜色的自定义属性。那么接下来就是直接上代码了。
我们需要再定义一个画笔:

        boder_paint.setAntiAlias(true);
        boder_paint.setStyle(Paint.Style.STROKE);
        boder_paint.setColor(border_color);
        boder_paint.setStrokeWidth(border_width);

接下来我们就是直接画上去了。当然了,我们这边默认是不设置,也就是borderwidth为0,所以我们要加一个判断:

  if (type == TYPE_ROUND) {
            canvas.drawRoundRect(rectF, borderRadius, borderRadius,paint);
            if (border_width > 0) {
                canvas.drawRoundRect(rectF, borderRadius, borderRadius, boder_paint);
            }
        } else if (type == TYPE_CIRCLE) {
            canvas.drawCircle(radius, radius, radius, paint);
            if (border_width > 0) {
                canvas.drawCircle(radius, radius, radius, boder_paint);
            }
        } else {
            getDrawable().draw(canvas);
        }

这里写图片描述
我们一编译,一运行,效果炸了。你问我为什么?我们先来看个效果在说把。
这里写图片描述
我们发现我们修改的fitxy属性已经生效了。但是,为什么加了边框是这样呢?
仔细想想。我们画圆角和圆的时候是不是忘记去掉了边框的宽度呢?那么我们既然找到了原因就可以找到解决方法了。那我们就直接去掉边框的高度,注意!!圆角和圆的都要处理。

   canvas.drawCircle(radius, radius, radius, paint);
            if (border_width > 0) {
                canvas.drawCircle(radius, radius, radius - border_width / 2, boder_paint);
            }

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (type == TYPE_ROUND) {
            rectF = new RectF(border_width/2,border_width/2, getWidth()- border_width / 2, getHeight()- border_width / 2);
        }
    }

我们再来看下效果:
这里写图片描述
搞定。完美~

使用

在gradle加上如下代码:

compile 'com.angel:SWImageView:1.0.0' 

关于自定义属性:

<declare-styleable name="SWImageView">
        <attr name="borderRadius" format="dimension"/>
        <attr name="type">
            <enum name="normal" value="-1"/>
            <enum name="circle" value="0"/>
            <enum name="round" value="1"/>
        </attr>
        <attr name="borderWidth" format="dimension" />
        <attr name="borderColor" format="integer" />
    </declare-styleable>

我觉得命名很清晰明了。我就不介绍了。
项目我已上传到github:https://github.com/sw950729/SWImageView 喜欢的朋友随手点了star。谢谢。

查看评论

Android开发:ImageView 设置圆角边框

应用情形:1、给头像添加一个边框(不一定是圆角边框,此处顺带讲解圆角边框)     2、其它涉及图像使用ImageView的情形 讲 解:设置ImageView 带必然宽度的Padding,同时设...
  • talktokevin
  • talktokevin
  • 2013-11-27 17:02:15
  • 8297

自定义圆角带边框ImageView

最近项目改版需要带阴影的圆角矩形,最后只实现了带边框的圆角矩形,阴影需要渐变,由于宝宝经验有限,只能参考被人的实现成了这样的。有路过的大神可以留下脚印,嘿嘿import android.content...
  • hello_1s
  • hello_1s
  • 2016-09-21 10:02:15
  • 1443

安卓自定义<em>view</em>之圆形<em>圆角ImageView</em>

圆形、<em>圆角ImageView</em> 立即下载 上传者: lx0017 时间: 2014-11-10 综合评分: 5 积分/C币:3 圆形,<em>圆角</em>,带<em>边框</em>的圆形<em>imageView</em> 立即下载 上传者: ggcy 时...
  • 2018年04月13日 00:00

给UIImageview 添加边框 或者设置成圆角

//设置layer CALayer *layer=[backView layer]; //是否设置边框以及是否可见 [layer setMasksToBounds:YES]; ...
  • chengyakun11
  • chengyakun11
  • 2012-06-16 10:15:04
  • 18499

设置ImageView圆角及边框问题

RoundedDrawable.java package com.llkj.carfocus.myview.makeramen; import android.content.res.ColorS...
  • u011402761
  • u011402761
  • 2014-08-08 16:15:36
  • 1991

自定义圆角ImageVIew

今天继续写写博客,坚持下去懒癌是有救的。这个控件可以给图片带上圆角矩形或者圆形效果,并可以设置外带的边框。废话少说,先看看事例图: 上面两个就是正圆和圆角矩形的效果啦。它会自动缩放图片使之中...
  • huangmayi
  • huangmayi
  • 2017-05-23 23:51:39
  • 621

Android ImageView圆角,绘制ImageView边框;Bitmap圆角

因为项目中有ImageView圆角的需求,但是网上的例子都不尽如人意,所以自己写了一个,现将其粘贴出来,供各位大神点评. 首先说一下自己的实现思路: 1.通过自定义属性,定义圆角图片的圆角弧度;边...
  • u010947098
  • u010947098
  • 2015-03-26 19:54:49
  • 2163

Android实现圆形Imageview,带白色边框

最近做了个圆形Imageview,外面有白色边框 有需要的同学可以看看,效果如下     附上实现代码 RoundImageView: public class RoundImageV...
  • a_ycmbc
  • a_ycmbc
  • 2016-05-11 11:45:26
  • 4428

难以想象,这才是真正的日本(转载序)

难以想象,这才是真正的日本(转载序)var stattitle=/难以想象,这才是真正的日本(转载序)/;Leon发给我的一篇家电论坛的文章,内容真伪无从考证,仅供想了解日本的人参考。而我的态度当然是...
  • wecopy
  • wecopy
  • 2007-07-12 20:01:00
  • 205

全面屏新機旗艦

其采納了高通驍龍 835 處理器,內置 4GB / 6GB RAM,供應 64GB / 128GB ROM,運轉 Android 8.0 體系。克日, 爆料人 @Onleak 暴光了這款新機的襯著圖。...
  • linqqianduoduo
  • linqqianduoduo
  • 2017-10-21 13:27:30
  • 56
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 18万+
    积分: 2051
    排名: 2万+
    我的公众号
    博客专栏