仿有道云笔记头像背景

转自 仿有道云笔记头像背景 

前言

如题,本文模仿实现有道云笔记的侧滑菜单中的头像背景的效果,这一效果可用借鉴使用,毕竟大多数时候我们在应用上的资料可能没有像play、微博等的个人页面的自定义背景图。没用过这款应用的童鞋可以下载这款应用看看。

分析

先来看看有道云笔记上的图片(重点是头像上的背景图,真机看起来效果比较好):
有道云笔记效果图

有道云笔记效果图

在手机上没找到背景的效果图,应该是在手机上生成的效果图,根据它的背景图片可以看出图片时黑白的而且是有点朦胧感,所以经过分析和实验得到做这一效果可以使用的方法:黑白效果用ColorFilter实现、模糊效果可以用RenderScript的API实现。代码的步骤也是先得到黑白的Bitmap再把它模糊处理。

黑白

Android中图片是以RGBA像素点的形式加载到内存中的,这些像素信息通过ColorMatrix,官方文档的描述如下:
4×5矩阵转换位图的颜色+ alpha分量。该矩阵存储在一个单独的阵列中,其进行如下处理:

\[ a, b, c, d, e,
f, g, h, i, j,
k, l, m, n, o,
p, q, r, s, t \]

当应用于ColorR,G,B,A,所以将上面矩阵跟图片的原值相乘后的结果:

R' = a\*R + b\*G + c\*B + d\*A + e;
G' = f\*R + g\*G + h\*B + i\*A + j;
B' = k\*R + l\*G + m\*B + n\*A + o;
A' = p\*R + q\*G + r\*B + s\*A + t;

所以ColorMatrix经ColorFilter就可以在Android中处理图片的颜色,关于这两个类更详尽的信息可以自己继续Google一下。而把图片变黑白就简单一些了,直接通过ColorMatrix的setSaturation)方法更改图片的饱和度即可,我们知道当图片的饱和度为0时就会变为黑白了。此外我们也可麻烦一点自己通过ColorMatrix调出一个合适的值也可以,这也是ColorMatrix的强大之处,下面是黑白效果的ColorMatrix的值:

float\[\] src = new float\[\]{
    0.28F, 0.60F, 0.40F, 0, 0,
    0.28F, 0.60F, 0.40F, 0, 0,
    0.28F, 0.60F, 0.40F, 0, 0,
    0, 0, 0, 1, 0,
};

所以黑白部分的处理代码:

Drawable drawable = getResources().getDrawable(R.drawable.rocko);
Bitmap srcBitmap = BitmapUtils.drawable2Bitmap(drawable);
/\*先黑白图片\*/
float\[\] src = new float\[\]
{
    0.28F, 0.60F, 0.40F, 0, 0,
    0.28F, 0.60F, 0.40F, 0, 0,
    0.28F, 0.60F, 0.40F, 0, 0,
    0, 0, 0, 1, 0,
};
ColorMatrix cm = new ColorMatrix(src);
// cm.setSaturation(0.0f);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
Bitmap resultBitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
Bitmap.Config.ARGB\_8888);
Canvas canvas = new Canvas(b);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setAlpha(100);
paint.setColorFilter(f);
canvas.drawBitmap(srcBitmap, 0, 0, paint);

模糊

模糊的效果处理可以有几种方式:Java、jni、Android的RenderScript API,Java代码的一种比较快的一种模糊算法实现fastBlur效果不太理想,还是比RenderScript慢些,所以最终采用Android官方的API实现RenderScript support v8的支持包,Android support v8支持包是在...\build-tools\21.1.2\renderscriptSDK的这里的,在Android Studio中使用support v8:在build.gradle的defaultConfig中加上下面两句即可,

renderscriptTargetApi 21
renderscriptSupportModeEnabled true

所以模糊部分的处理:

/\*后模糊图片\*/
Bitmap bB = BitmapUtils.blurBitmap(getApplicationContext(), resultBitmap, 15.5f);
//RenderScript模糊处理的使用,主要就是Allocation 、ScriptIntrinsicBlur、RenderScript这几个类,RenderScript里基本上是jni的本地代码了,不再展开
public static Bitmap blurBitmap(Context applicationContext, Bitmap bitmap, float radius)
{
    //Let's create an empty bitmap with the same size of the bitmap we want to blur
    Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB\_8888);
    //Instantiate a new Renderscript
    RenderScript rs = RenderScript.create(applicationContext);
    //Create an Intrinsic Blur Script using the Renderscript
    ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8\_4(rs));
    //Create the Allocations (in/out) with the Renderscript and the in/out bitmaps
    Allocation allIn = Allocation.createFromBitmap(rs, bitmap);
    Allocation allOut = Allocation.createFromBitmap(rs, outBitmap);
    //Set the radius of the blur
    blurScript.setRadius(radius);
    //Perform the Renderscript
    blurScript.setInput(allIn);
    blurScript.forEach(allOut);
    //Copy the final bitmap created by the out Allocation to the outBitmap
    allOut.copyTo(outBitmap);
    //recycle the original bitmap
    bitmap.recycle();
    //After finishing everything, we destroy the Renderscript.
    rs.destroy();
    return outBitmap;
}

工作完成,最后要注意的是模糊效果的处理是比较耗时的(~250ms),所以在UI线程里直接处理的话肯定会掉帧,16ms是界限值,建议开线程预先处理好再设置。仿照的效果图如下:
仿照效果图

仿照效果图

End

本文demo地址