稀有猿诉

十年磨一剑,历炼出锋芒,说话千百句,不如码二行。

优秀代码赏析:CircleImageView

核心功能

实现一个圆形的ImageView,或者说让一个View来显示一个圆形的图片。

核心思路

这个库短小精悍,全部代码才200多行,核心代码也就几十行,却实现了一个看似不简单的功能。

要想实现圆形的图片,常规一般的人的思路,用图像处理的方式来解决,就好比显示圆角矩形图片那样。但是这个库的作者的思路十分的巧妙,它的核心思路就是把图片画在一个圆上面。

首先要解释一下Shader(着色器)的概念,它的作用就是如何填充一个几何图形,图像学里面画一个可见的几何图形分二步,一个画形,另一个就是着色。比如我们常用的shape或者text,除了形状外,还有颜色,这也是一种着色方式,只不过是我们熟悉的颜色罢了。Shader最为常见的就是颜色,另外还可以是其他几何图形,纹理和图片。比如PhotoShop里面画东西时刷子的样式有无数种,矩形,三角,球,毛状的,其他图像等等,这也都是Shader。在Android中支持的Shader有颜色,也还有图片(Bitmap),也就是说可以把一个图片当成着色器,来画在几何形状上面,这也就是这个库的精妙所在。

关键代码解析

准备资源

这里的资源包括二个,一个是图片资源,另一个就是边缘的颜色。圆形外面还有一个border。图片资源跟标准的ImageView是一样的,可以是资源,可以是URI,可以是Drawable也可以是Bitmap。这些东西都要要转化成为Bitmap,再生成BitmapShader放在Paint对象里。

绘制

这个类的绘制是相当简单的,onDraw的关键代码只有二行,只做了二件事:

  • 用BitmapShader画一个圆
  • 用border颜色画一个圆的边缘

缩放

仅支持CenterCrop,缩放方式。也就是把图片等比缩放(也就是长和宽都按同一比例来缩放,以保证图片不变形),以让最小的边刚好占满View的区域,大的一边如果超出会进行Crop。

为了进行CenterCrop,就要计算出View区域长宽与图片长宽的最大比例,然后把图片长和宽都以此为比例来缩放。再把超出的一边进行Crop。

详细的来解释下,如图所示,vw为目标View的区域的宽度,vh为目标区域高度,bw为图像的宽,bh为图像的高,只能是二种情况:过宽或者过高,图示第一种情况,明显是过高,所以缩放比例为vh/bh,按此比例缩放后nbw = bw*vh/bh > vw,所以要进行裁剪,左右各裁剪掉(nbw - vw)/2;对于第二情况也是如此。至于作者在translate时,为何都多加了个0.5个像素,是为了做round(四舍五入),前面计算dx和dy时会做除2,而移动必须是以整数像素为单位,所以要做下round。

项目地址

https://github.com/hdodenhof/CircleImageView

如何使用

优秀的库都是非常的易学易用,这个也不例外,简单来个例子:

1
2
3
4
5
6
7
8
<de.hdodenhof.circleimageview.CircleImageView
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:layout_width="160dp"
            android:layout_height="160dp"
            android:layout_centerInParent="true"
            android:src="@drawable/hugh"
            app:border_width="2dp"
            app:border_color="@color/dark" />

就像使用标准ImageView那样使用就好了,仅是多了特有的前缀来指定它需要的参数。更详细的可以参考官方的Sample

Comments