公司项目中有一个需求,需要在一个游戏列表顶部显示一个由此列表中游戏图标拼接而成的图片。
就是类似知乎的这种效果。
初步思路:1.获得图片地址并下载图片
2.根据下载的图片拼接一张大图片
3.图片旋转45度
开搞:
第一步:怎么下载图片:
这个比较简单,项目使用的是Sketch框架类似Fresco,大家可以根据自己的项目修改:
将下载完成的Drawable 保存到bitmapList中,当全部图片下载完成后,进行拼接。
bitmapList,显示区域的宽和高 作为参数传入makeWithDrawable ()。
Sketch.with(context).load(urlList.get(i), new LoadListener() {
@Override
public void onStarted() {
}
@Override
public void onCompleted(Drawable drawable, ImageFrom imageFrom, String mimeType) {
bitmapList.add(drawable);
compeletedNum++;
if (compeletedNum == urlList.size()) {
Bitmap finalBitmap = makeWithDrawableList(bitmapList, width, height);
imageView.setImageBitmap(finalBitmap);
}
}
@Override
public void onFailed(FailCause failCause) {
}
@Override
public void onCanceled(CancelCause cancelCause) {
}
}).commit();
第二部,怎么拼成一张大图片?
首先需要创建一个bitmap出来
Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
高度和宽度怎么确定呢?
看效果图,整个大图片需要12张小图片拼接出来(4*3)。每张小图片的宽度大概是最终显示区域宽度的0.5倍,高度是0.6倍。所以大图片的宽度是小图片宽度的3倍,高度是小图片高度的四倍。
开始画吧。。。
从bitmapList数组中遍历去取drawable对象,这里为了减少内存开销只由前张图片进行拼接。
拿到drawable之后,开始从左到右,从上到下画图片,new 一个Canvas对象。
这里通过drawable.setBounds()
指定一个矩形区域,然后通过draw(Canvas)画的时候,就只在这个矩形区域内画图。
Canvas canvas = new Canvas(result);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 3; j++) {
drawable = bitmapList.get((i * 3 + j) % bitmapList.size());
drawable.setBounds(smallWidth * j, smallHeight * i, smallWidth * (j + 1), smallHeight * (i + 1));
drawable.draw(canvas);
}
}
现在大图片Bitmap上面已经绘制了12张小图片,还差最后一步旋转。
第三部:旋转怎么做?
这里有一个技巧就是旋转画布:就是说你把画布旋转45度,再去画,就相当去图片旋转了45度。
Bitmap bmp = Bitmap.createBitmap(needWidth, needHeight, Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bmp);
canvas.rotate(45, needWidth, needHeight * 0.3f);
Paint paint = new Paint();
canvas.drawBitmap(bitmap, 0, 0, paint);
这样就完成了。最后加了一个内存缓存,用图片集的URL拼接了key。
防止频繁进入和退出时的内存消耗。
详情请参见Github:
https://github.com/Davidrou/AssembleImage
最终效果图: