️This article has been over 2 years since the last update.
目前有很多厂家/APP都在做Blur,比如魅族高端机(mx4以后的机器)提供了实时模糊选项,并给第三方相应的sdk。有的第三方app(比如最美壁纸,雅虎天气,开眼等)看似使用了实时模糊,实际上只是两张截图的alpha变换而已,网上大多数开源项目亦是如此;还有的第三方库,比如14年非常火的GlassActionbar,的确可以实现动态模糊,可是fps不太满意,而且内部使用了AsyncTask
作为异步处理,考虑到线程池中创建,销毁,上下文切换的损失,也不太敢用。
最后,面向Github编程的我,经过各种坑,终于抄到了一个项目
500px-android-blur,这个项目貌似是一位肉翻的国人写的,代码质量很高,英文写的也很正统。经过阅读参考代码后,我把自定义view中的相关处理port到了Drawable中,这个就是今天的主题BlurDrawable,本文就此分享一下使用与源码。
使用
首先要有两个view,一个盖在另一个上面,比如说最常见的NavigationBar
与RecyclerView
,它们放在一个FrameLayout中,然后进行如下代码:
1 | BlurDrawable drawable = new BlurDrawable(mRvFragCard); |
如果你的需求只是静态模糊,那么所有东西就已经写完了,如果需要在滚动时进行实时计算,按照下面写的在滚动时通知重绘即可。
1 | mRvFragCard.addOnScrollListener(new RecyclerView.OnScrollListener() { |
这里还有个小技巧,如果按照默认布局的话,启动时RecyclerView的第一个item会嵌入在NavigationBar中无法点击,所以需要预留一些padding空间
1 | <android.support.v7.widget.RecyclerView |
这样使用效果就如上面gif一样了,gif压缩了部分细节,建议下载完整示例程序查看
最后,当不需要时,释放资源
1 | protected void onDestroy() { |
兼容性与效率
基于自带的RenderScript
进行渲染,厂商与谷歌都进行了专业的优化,所以兼容性与效率当然是棒棒哒,然而在国内…
1. 兼容性正常的机器:
- API17及以上: 将自动开启Blur,经过玄学曲线进行测试,构造耗时4ms,滚动时fps在8ms左右(在高通615/1080P/2G下进行测试的,615的尿性大家都知道,也就是说目前千元机均毫无压力);
- API17以下: 它将自动根据
OverlayColor
当做ColorDrawable进行纯色绘制(iOS关闭blur后也是这样的效果)。如果非要强迫用blur的话,可以使用RenderScript
的兼容包,但不推荐。
2. 兼容性不正常的机器:
根据群里大神的建议,某些国产设备由于ROM偷工减料,可能会出现RenderScript崩溃或者性能不达标的坑。不过跑了下Testin云测,随机100个主流设备并没有出现因为RenderScript崩溃的案例,但是出现了一个山寨机花屏的问题。另外根据友盟指数可以看到,TOP50的设备中,除了酷派的老设备,其它都是比较放心的不会偷工减料的厂商。
综上,我个人还是建议集成,第一,它只是个单文件,定制强,体积小的不像实力派;第二,可以通过drawable.setEnabled(false)
手动控制默认开关;
开发者如果想在兼容性与美观性保持平衡的话,建议在设置中默认关闭,并引导用户开启;或者将API17手动提高到19或者20,以获得更好的兼容性。
原理分析
实时渲染非常类似于DSP,底层是c语言实现的高斯模糊。首先根据DownsampleFactor
进行绘制与抽样,获取到被覆盖view的rawBitmap,这样bitmap的信息量减小了几个数量级(比如1920x1080
缩小到136x244
),接着通过Renderscript进行卷积运算编码后输出,最后将处理好的bitmap用canvas拉伸绘制到表层的view中。注释已经很详细了,这里就不说了。