android开发万能圆角ImageView

来源:互联网 发布:dictionary软件下载 编辑:程序博客网 时间:2024/05/22 19:39

转载请注明出处:http://blog.csdn.net/sw950729/article/details/52037798
本文出自:马云飞的博客
本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布
最近一两个月没事做,然后就开始封装一些东西,昨天上司让我帮他做的圆角图片。思路自然是和网上的demo不一样的。
网上demo的效果:
这里写图片描述
差不多应该是这样的,但是容易出一些问题,比如你的图片本身就是个圆角?又或者图片太大,你想缩小显示,但出现显示内容不全?
我想实现的效果是这样的:
这里写图片描述
图画的较丑,见谅。
意思就是以他的宽高的最小值,为正方形的宽给他做圆角,当然长方形也可以的,因为我试了效果,没有问题,你们到时候可以自己尝试。
参考文章:http://blog.csdn.net/lmj623565791/article/details/41967509
这是翔神的文章,不过他的效果,并不是我想要的,因为,他的绘图是从(0,0)点然后截取宽高绘图,并不是我想要的重中间截取,然后绘图。
大体代码和他的差不多。不过依旧删除了一些无用的代码(哈哈,这个我抄代码的特性,没用放着干嘛,碍眼。)
好了下面上代码:
初始化:

  private void inital(Context context, AttributeSet attrs) {        matrix = new Matrix();        paint = new Paint();        //无锯齿        paint.setAntiAlias(true);        TypedArray array = context.obtainStyledAttributes(attrs,                R.styleable.RoundAngelImageView);        //如果没设置圆角的默认值,在这设置默认值为10dp        BorderRadius=dp2px(BODER_RADIUS_DEFAULT);        // 默认为Circle        type = array.getInt(R.styleable.RoundAngelImageView_type, TYPE_CIRCLE);        array.recycle();    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

这边我用到了dp2px。这个就是将dp转换成px。网上代码一堆~~~~:

 public int dp2px(int dp) {        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,                dp, getResources().getDisplayMetrics());    }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

既然继承了ImageView,少不了的自然是onmeusre方法:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        //如果类型是圆形,则强制改变view的宽高一致,以小值为准        if (type == TYPE_CIRCLE) {            width = Math.min(getMeasuredWidth(), getMeasuredHeight());            radius = width / 2;            setMeasuredDimension(width, width);        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

下面就是重点了,对bitmapshader不了解的,去看看这个:http://blog.csdn.net/aigestudio/article/details/41799811

设置bitmapshader的代码如下:

  Drawable drawable = getDrawable();        if (drawable == null) {            return;        }        //将drawable转化成bitmap对象          Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();        if (bitmap == null) {            return;        }        // 将bmp作为着色器,就是在指定区域内绘制bmp        BitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);        float scale = 1.0f;        int viewwidth = getWidth();        int viewheight = getHeight();        int drawablewidth = bitmap.getWidth();        int drawableheight = bitmap.getHeight();        float dx = 0, dy = 0;        if (type == TYPE_CIRCLE) {            // 拿到bitmap宽或高的小值            int size = Math.min(bitmap.getWidth(), bitmap.getHeight());            scale = width * 1.0f / size;        } else if (type == TYPE_ROUND) {            // 如果图片的宽或者高与view的宽高不匹配,计算出需要缩放的比例            // 缩放后的图片的宽高,一定要大于我们view的宽高;所以我们这里取大值            scale = Math.max(getWidth() * 1.0f / bitmap.getWidth(), getHeight()                    * 1.0f / bitmap.getHeight());        }        if (drawablewidth * viewheight > viewwidth * drawableheight) {            dx = (viewwidth - drawablewidth * scale) * 0.5f;        } else {            dy = (viewheight - drawableheight * scale) * 0.5f;        }        // shader的变换矩阵,我们这里主要用于放大或者缩小        matrix.setScale(scale, scale);        matrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));        // 设置变换矩阵        BitmapShader.setLocalMatrix(matrix);        // 设置shader        paint.setShader(BitmapShader);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

如果有人看了前面我给的参考文章,那么,你可以发现,我把这个类的代码进行了改动,差不多就是把图片的起点坐标从(0,0)移动到了我想要的起点。
至于为什么,我们打开ImageView的源码,找到Center_Crop。这快代码的意思差不多是将图片居中把。
来,我们上源码:

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((int) (dx + 0.5f), (int) (dy + 0.5f));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

他怎么计算的scale我们别管它,重点是如何计算他的dx和dy。
这里我就举个例子来计算。drawable的宽和高是(300,200)。我要绘制的view的宽高是(200,200)。按照 我的思路绘图是从(50,0)到(250,250),而不是(0,0)到(200,200)。
话不多说。我们看源码的计算:

dw*vh=300*200;dh*vw=200*200;/*此时我们需要得到dx的值,dy默认为0,我的起点是(50,0),似乎是对的?我们接着计算*/  scale = Math.max(getWidth() * 1.0f / bitmap.getWidth(), getHeight()* 1.0f / bitmap.getHeight());/**那么我们的scale=math.max(200/300,200/200)=1*/  dx = (vwidth - dwidth * scale) * 0.5f;  /**  那么dx=(200-300*1)*05=-50,和我想要的50越来越近的,那么为什么他postTranslate的时候是(-50,0)而不是(50,0)?  */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

我们画图,来说明这一切,看完图,你或许就懂了。
这里写图片描述
红色框是我们之后的,那这样,1这块区域可以理解成没了。销毁了。但是实际的效果是这样:
这里写图片描述
圆形好像看似没什么问题,那你们自己看圆角图片左边是不是被拉伸,这个拉伸距离应该刚好是我们之前计算得到的50dp。因为上图的1那块已经不存在了,所以你画图的时候那快距离就是拉伸的距离。现在我们看看-50dp的图。
这里写图片描述
1的部分被移出去了。但他依然是存在的,所以绘制的图是不会出现任何拉伸的。perfect~~~。
属性配置完了,剩下的就是ondraw方法咯。很简单,代码如下:

protected void onDraw(Canvas canvas) {        if (getDrawable() == null) {            return;        }        setBitmapShader();        if (type == TYPE_ROUND) {            canvas.drawRoundRect(rectF, BorderRadius, BorderRadius,                    paint);        } else {            canvas.drawCircle(radius, radius, radius, paint);        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

当然你也得考虑到onsizechanged的时候,代码也不多:

 protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        // 圆角图片的范围        if (type == TYPE_ROUND)            rectF = new RectF(0, 0, getWidth(), getHeight());    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

好了。在这边我补上attrs属性:

 <attr name="borderRadius" format="dimension" />    <attr name="type">        <enum name="circle" value="0" />        <enum name="round" value="1" />    </attr>    <declare-styleable name="RoundAngelImageView">        <attr name="borderRadius" />        <attr name="type" />    </declare-styleable>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

现在。一个完美的,万能的圆角ImageVIew就解决了。不过好像还缺点什么,对了。自行修改圆角,自行修改类型,加上这个才算完美。
附上代码:

  //修改圆角大小    public void setBorderRadius(int borderRadius) {        int px = dp2px(borderRadius);        if (this.BorderRadius != px) {            this.BorderRadius = px;            invalidate();        }    }    //修改type    public void setType(int type) {        if (this.type != type) {            this.type = type;            if (this.type != TYPE_ROUND && this.type != TYPE_CIRCLE) {                this.type = TYPE_CIRCLE;            }            requestLayout();        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

现在我们新建个xml。放2张图片。一个圆角,一个圆形,先看看效果如何:

  <LinearLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        android:orientation="vertical">        <sw.angel.roundangelimageview.RoundAngelImageView            android:layout_width="200dp"            android:layout_height="200dp"            android:layout_marginTop="30dp"            android:layout_gravity="center"            android:src="@drawable/myimage" />        <sw.angel.roundangelimageview.RoundAngelImageView            android:layout_width="200dp"            android:layout_height="200dp"            android:layout_marginTop="30dp"            android:layout_gravity="center"            android:src="@drawable/mine"            sw:type="round" />    </LinearLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

多张图片在外层加一个scrollview。好了。我们来看一下效果:
这里写图片描述
完美~~
圆角大小自行修改。类型自行修改。好了。今天主要内容就这么多把。
整理了2个多小时~也是够够的。
感觉还有一些常用的控件,带删除键的edittext。以及可见不可见的edittext。似乎不难。(有空在研究)。
最后,问你们个问题,忙活了一天没解决。你们用Android.suport.design包是怎么用的。为什么我rebuild之后是这样。
这里写图片描述
这是什么鬼。不懂。
好了,今天就说到这边把,能解决我问题的请留言,谢谢。我的android交流群:232748032。欢迎加入。

0 0
原创粉丝点击