今天项目中即时通信工具部分要把好友头像由方形转换成圆形,大概也是跟上时代的潮流吧,毕竟连 QQ 都开始使用圆形头像了,我在这里记录一下修改过程。
在网上找了一番之后,大概解决方法有两种
使用自定义组件继承 ImageView
通过对 BitMap 重绘得到
第一种方式,有许多开源框架可以实现,如 CircleImageView ,由于我们项目中图片缓存及显示使用的是 Android-Universal-Image-Loader ,而他本身支持在获取到网络图片之后增加回调,那我毫无疑问的选择了第二种方式实现,
首先是圆形图片转换的方法
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 public static Bitmap getRoundedCornerBitmap (Bitmap bitmap) { int width = bitmap.getWidth(); int height = bitmap.getHeight(); Bitmap output = Bitmap.createBitmap(width, height, Config.ARGB_8888); Canvas canvas = new Canvas(output); int minLength = width > height ? height : width; final int color = 0xff424242 ; final Paint paint = new Paint(); int x = (width - minLength) / 2 ; int y = (height - minLength) / 2 ; final Rect rect = new Rect(x, y, x + minLength, y + minLength); final RectF rectF = new RectF(rect); final float roundPx = minLength / 2 ; paint.setAntiAlias(true ); canvas.drawARGB(0 , 0 , 0 , 0 ); paint.setColor(color); canvas.drawRoundRect(rectF, roundPx, roundPx, paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); canvas.drawBitmap(bitmap, rect, rect, paint); return output; }
再然后是显示图片工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static SimpleImageLoadingListener listener;public static <T extends ImageView> void displayImage2Circle (T container, String url) { if (listener == null ) { listener = new SimpleImageLoadingListener() { @Override public void onLoadingComplete (String imageUri, View view, Bitmap loadedImage) { super .onLoadingComplete(imageUri, view, loadedImage); ((ImageView) view).setImageBitmap(getRoundedCornerBitmap(loadedImage)); } }; } ImageLoader.getInstance().displayImage(url, container, listener); }
这样只要是需要把图片显示为圆形的地方直接调用 displayImage2Circle 这个方法即可
本以为已经大功告成,没想到使用之后却发现图片四周仿佛被切掉一部分一样,如图:
起先以为是图片有白边,后来发现不是,图片地址
然后又以为是半径没算对,验证之后再次被排除
最终把原因定位到了 Image-Loader 上,解决办法如下:
ImageLoaderConfiguration 的 defaultDisplayImageOptions 方法需要一个 DisplayImageOptions 参数而 DisplayImageOptions 的参数的 imageScaleType 属性默认的是 ImageScaleType.IN_SAMPLE_POWER_OF_2 就是这个属性导致的图片不圆,查了一下文档
1 2 3 4 5 6 7 8 9 10 imageScaleType(ImageScaleType imageScaleType) imageScaleType: EXACTLY :图像将完全按比例缩小的目标大小 EXACTLY_STRETCHED:图片会完全缩放到目标大小 IN_SAMPLE_INT:图像将被二次采样,并且倍数为整数倍 IN_SAMPLE_POWER_OF_2:图片将降低2 倍,直到下一减少步骤,使图像更小的目标大小 NONE:图片不会调整
IN_SAMPLE_POWER_OF_2 模式下缩放是成倍缩放的所以导致实际显示的要比我设定的宽一些,改成 EXACTLY_STRETCHED 之后问题得到解决
最后展示一下最终效果
以及 Image-Loader 的完整设置
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 private void initImageLoader () { DisplayImageOptions options = new DisplayImageOptions.Builder() .showImageForEmptyUri(R.drawable.default_image) .showImageOnFail(R.drawable.default_image) .imageScaleType(ImageScaleType.EXACTLY_STRETCHED) .bitmapConfig(Config.RGB_565) .cacheInMemory(true ) .cacheOnDisk(true ) .resetViewBeforeLoading(true ) .build(); File cacheDir = StorageUtils.getOwnCacheDirectory(getApplicationContext(), Util.getCachePath()); ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this ) .denyCacheImageMultipleSizesInMemory() .memoryCache(new LruMemoryCache(2 * 1024 * 1024 )) .threadPoolSize(4 ) .memoryCacheSize(2 * 1024 * 1024 ) .diskCache(new UnlimitedDiscCache(cacheDir)) .diskCacheSize(50 * 1024 * 1024 ) .diskCacheFileCount(100 ) .defaultDisplayImageOptions(options) .build(); ImageLoader.getInstance().init(config); }
公司项目我就不放源码了,核心代码都在上面了,有问题可以和我联系。