关于Fresco加载图片的处理,例如旋转、裁剪切割图片,在官方文档也都有提到,只是感觉写的不太详细,正好最近项目里有类似需求,所以分享一些使用小tip,后面的朋友就不用再走弯路浪费时间了。(测试图片分辨率1200*800)
原图:
裁剪图片实现
旋转图片
1 | /** |
使用效果:
监听图片下载
首先构造监听器:
1 | //监听图片下载进度,这里只重写了onFinalImageSet,当图片下载完成时获得图片宽高等信息 |
1 | /** |
如果我想要1:1在手机端展示呢?
我首先想到的是1:1按照图片的尺寸设置SimpleDraweeView的宽高并设置缩放方式为fitXY,但是果不其然,view超出屏幕的部分是无效的。
裁剪切割图片
既然view超出屏幕无效,那就曲线救国,让图片超出屏幕部分不显示在view里就好了。
裁剪图片首先要写一个processor类:
1 | /** |
然后在ImageRequest里setProcessor:
1 | /** |
调用方法:
1 | mImageView.setLayoutParams(new RelativeLayout.LayoutParams(600, 400)); |
图片是1200800的,这里设置view的宽高为600400,可以看到图片成功裁剪只保留原图左上四分之一。通过设置view宽高,配合裁剪图片,即可达到1:1显示的效果。
旋转+裁剪
如果是要旋转90度后再裁剪呢?那还不简单,直接在裁剪的基础上,在ImageRequest里调用旋转方法不就好了。
1 | /** |
然后调用:
1 | //例如我需要旋转90度且宽度不变,高度方向裁剪掉一半(即保留(0,0)-(1200,400)) |
然而得到的并不是我们想要的
可以看到得到的是左半边(0,0)-(600,800)的图,即宽度方向被裁剪掉一般,高度方向不变,明明我在cutProcess里是设置宽度方向不变,高度方向裁剪50%,但是因为旋转了90度,结果却正好相反。难道是因为旋转90度后横纵方向也发生改变?那调换一下横纵方向的切割比例试试看:
1 | CutProcess cutProcess = new CutProcess(0, 0, 0.5f, 1f); |
可以看到,调换横纵切割比例后,却得到的是下半边(0,400)-(1200,800)。还是不正确,难道是原点也改变了?再测试一下,如果要裁剪后保留右下四分之一(600,400)-(1200,800)区域,正常无旋转的情况下是这样的:
1 | mImageView.setLayoutParams(new RelativeLayout.LayoutParams(600, 400)); |
但如果旋转270度后,同样代码得到的结果却是这样的:
看到这里我们就清楚了,旋转图片后,其实(0,0)点,也就是所谓的原点也随之变换。默认情况下,原点是(0,0),顺时针旋转90度后,原点就变成了(0,800),以此类推旋转180度原点为(1200,800),旋转270度原点为(1200,0)(和旋转后的图片的左上角相对应)。虽然是在构建ImageRequest时同时传入旋转和裁剪参数的,但实际上可以看作是先完成了旋转,然后在旋转后的基础上,以屏幕的左上角为原点,左上角往右为x正方向,左上角往下为y正方向。
小试牛刀一下,旋转270度后,想要裁剪后只保留原图的左上四分之一(0,0)-(600,600),那推测就应该是(0, 0.5f, 0.5f, 0.5f)。
1 | mImageView.setLayoutParams(new RelativeLayout.LayoutParams(400, 600)); |
Bingo!推测正确。
旋转+裁剪就是这个原点的变换要注意下。另外看代码里的几个方法,裁剪、旋转、获得宽高等,有没有觉得老是要重复写PipelineDraweeController、ImageRequest的代码好麻烦啊。其实裁剪、旋转等方法无非也就是添加一个参数,类似这种可变参数的复杂类的构造可以使用Builder模式封装一下。封装代码就不贴在这里了。demo下载地址
1 | //Builder模式封装后 |
使用Matrix实现
继承 SimpleDraweeView 自定义控件,使用Matrix实现旋转缩放:
1 | public class MyFresco extends SimpleDraweeView { |
就是酱~