拿到一个小说详情页的设计稿,顶部要用小说的封面图做高斯模糊。然后在与下半部分界面过渡时,要保持平滑过渡。一般像小说的封面和音乐的专辑封面之类的图片,拿到的图片深色系、浅色系的都会有,以及各种排版的图片都有,要保障所有图片显示都没问题。写篇文章,记录下实现过程。
此处需要平滑过渡 小说详情页设计稿一开始,尝试用图片直接做高斯模糊。但是会发现边缘处会有明显的分割线。很明显做不到,需求需要的过渡平滑。
最后选择的解决方案如下:
- 将封面图用代码,直接裁剪一部分。
Bitmap coverBitmap = BitmapUtils.cropBitmap(bitmap);
/**
* 裁剪中间
*
* @param srcBmp 原图
* @return 裁剪后的图像
*/
public static Bitmap cropBitmap(Bitmap srcBmp) {
Bitmap dstBmp;
if (srcBmp.getWidth() >= srcBmp.getHeight()){
dstBmp = Bitmap.createBitmap(
srcBmp,
srcBmp.getWidth()/2 - srcBmp.getHeight()/2,
0,
srcBmp.getHeight(),
srcBmp.getHeight()
);
}else{
dstBmp = Bitmap.createBitmap(
srcBmp,
0,
srcBmp.getHeight()/2 - srcBmp.getWidth()/2,
srcBmp.getWidth(),
srcBmp.getWidth()
);
}
return dstBmp;
}
- 将一个纯白色的长方形图(用代码生成也可以),拿到的 bitmap 与用封面图裁剪的图,做上下拼接。
whiteRectBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.white_rect)
newBitmap = BitmapUtils.combineImage(coverBitmap, whiteRectBitmap);
/**
* 拼接图片
*
* @param bitmaps 原图片集
* @return 拼接后的新图
*/
public static Bitmap combineImage(Bitmap... bitmaps) {
boolean isMultiWidth = false;//是否为多宽度图片集
int width = 0;
int height = 0;
//获取图纸宽度
for (Bitmap bitmap : bitmaps) {
if (width != bitmap.getWidth()) {
if (width != 0) {//过滤掉第一次不同
isMultiWidth = true;
}
width = width < bitmap.getWidth() ? bitmap.getWidth() : width;
}
}
//获取图纸高度
for (Bitmap bitmap : bitmaps) {
if (isMultiWidth) {
height = height + bitmap.getHeight() * width / bitmap.getWidth();
} else {
height = height + bitmap.getHeight();
}
}
//创建图纸
Bitmap newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
//创建画布,并绑定图纸
Canvas canvas = new Canvas(newBitmap);
int tempHeight = 0;
//画图
for (int i = 0; i < bitmaps.length; i++) {
if (isMultiWidth) {
if (width != bitmaps[i].getWidth()) {
int newSizeH = bitmaps[i].getHeight() * width / bitmaps[i].getWidth();
Bitmap newSizeBmp = resizeBitmap(bitmaps[i], width, newSizeH);
canvas.drawBitmap(newSizeBmp, 0, tempHeight, null);
tempHeight = tempHeight + newSizeH;
newSizeBmp.recycle();
} else {
canvas.drawBitmap(bitmaps[i], 0, tempHeight, null);
tempHeight = tempHeight + bitmaps[i].getHeight();
}
} else {
canvas.drawBitmap(bitmaps[i], 0, tempHeight, null);
tempHeight = tempHeight + bitmaps[i].getHeight();
}
bitmaps[i].recycle();
}
return newBitmap;
}
public static Bitmap resizeBitmap(Bitmap bitmap, int newWidth, int newHeight) {
float scaleWidth = ((float) newWidth) / bitmap.getWidth();
float scaleHeight = ((float) newHeight) / bitmap.getHeight();
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap bmpScale = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
return bmpScale;
}
- 将拼接后的图片,进行高斯模糊。
/**
* 高斯模糊
* @param context
* @param source
* @param radius
* @return
*/
public static Bitmap rsBlur(Context context,Bitmap source,int radius){
Bitmap inputBmp = source;
RenderScript renderScript = RenderScript.create(context);
// Allocate memory for Renderscript to work with
final Allocation input = Allocation.createFromBitmap(renderScript,inputBmp);
final Allocation output = Allocation.createTyped(renderScript,input.getType());
// Load up an instance of the specific script that we want to use.
ScriptIntrinsicBlur scriptIntrinsicBlur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript));
scriptIntrinsicBlur.setInput(input);
// Set the blur radius
scriptIntrinsicBlur.setRadius(radius);
// Start the ScriptIntrinisicBlur
scriptIntrinsicBlur.forEach(output);
// Copy the output to the blurred bitmap
output.copyTo(inputBmp);
renderScript.destroy();
return inputBmp;
}
- 最后,显示得到的高斯模糊后的图片,ImageView 可以加 android:alpha="0.3" 的透明度。
/**
* 显示顶部高斯模糊图片的背景
* @param bitmap
*/
private void showCoverBlur(Bitmap bitmap) {
Bitmap coverBitmap = BitmapUtils.cropBitmap(bitmap);
Bitmap whiteRectBitmap = BitmapUtils.drawable2Bitmap(getResources().getDrawable(R.drawable.white_rect));
Bitmap newBitmap = BitmapUtils.combineImage(coverBitmap, whiteRectBitmap);
Bitmap blurBitmap = BitmapUtils.rsBlur(BookDetailActivity.this, newBitmap, 25);
iv_white_rect_blur.setImageBitmap(blurBitmap);
}
5.记得在onDestory里清空bitmap
private void recycleBitmap(){
if (coverBitmap != null && !coverBitmap.isRecycled()) {
coverBitmap = null;
}
if (newBitmap != null && !newBitmap.isRecycled()) {
newBitmap = null;
}
if (whiteRectBitmap != null && !whiteRectBitmap.isRecycled()) {
whiteRectBitmap = null;
}
if (blurBitmap != null && !blurBitmap.isRecycled()) {
blurBitmap = null;
}
}
最后,显示的效果和设计稿想要的效果基本上是一致的。如果你也遇到类似需求,有其他更好的解决方案,欢迎留言交流。
网友评论