2025年4月1日 星期二 乙巳(蛇)年 正月初二 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > 安卓(android)开发

安卓的模糊视图

时间:12-14来源:作者:点击数:4
城东书院 www.cdsy.xyz

模糊效果可以生动地表现出内容的层次感,当使用者关注重点内容,即便在模糊表面之下发生视差效果或者动态改变,也能够保持当前背景。

在 IOS 设备中,我们首先构造一个 UIVisualEffectView,之后添加 visualEffectView 到 view 层,在 view 中可以进行动态的模糊。

  • UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
  • UIVisualEffectView *visualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];

安卓中的表现形式

我们在雅虎天气 APP 中确实看到了很好的模糊效果实例,但是根据 Nicholas Pomepuy 的博客帖子(link:http://nicolaspomepuy.fr/blur-effect-for-android-design/) ,然而,这个 App 是通过缓存一张预渲染的背景图片来实现图片虚化的。

虽然这种方法非常有效,但是确实不符合我们的需求,在 500px(link:https://500px.com/) 的 APP 中,图像通常是获得焦点的内容,而不仅仅是提供背景,这说明图像的变化很大且迅速,即便他们是在模糊层之下。在我们的安卓 APP中即是一个恰当的例子:当用户滑动至下一页时,整排图片会以相反方向淡出,为了组成所需的模糊效果,适当地管理多个预渲染图是困难的。

一种绘制模糊视图的方法

我们需要的效果是,实时地模糊其下的视图,最终需要给界面的是模糊视图的一个 blurred view 引用。

  • blurringView.setBlurredView(blurredView);

之后当 blurred view 改变时,不管是因为内容改变(比如呈现新的图片)、view 的变换还是处在动画过程,我们都要刷新 blurring view。

  • blurringView.invalidate();

为了实现 blurring view, 我们需要继承 view 类并重写 onDraw() 方法来渲染模糊效果。

  • protected void onDraw(Canvas canvas) {
  • super.onDraw(canvas);
  • // Use the blurred view’s draw() method to draw on a private canvas.
  • mBlurredView.draw(mBlurringCanvas);
  • // Blur the bitmap backing the private canvas into mBlurredBitmap
  • blur();
  • // Draw mBlurredBitmap with transformations on the blurring view’s main canvas.
  • canvas.save();
  • canvas.translate(mBlurredView.getX() - getX(), mBlurredView.getY() - getY());
  • canvas.scale(DOWNSAMPLE_FACTOR, DOWNSAMPLE_FACTOR);
  • canvas.drawBitmap(mBlurredBitmap, 0, 0, null);
  • canvas.restore();
  • }

这里的关键点在于,当模糊视图重绘时,它使用 blurred view 的 draw() 方法,模糊视图保持 blurred view 的引用,它绘制一个私有的,以 bitmap 作为背景的画布。

  • mBlurredView.draw(mBlurringCanvas);

这种使用另一个视图的 draw()方法,也适用于建立放大或者个性的 UI 界面,在其中,放大区域的内容是扩大的,而不是模糊的。

根据 Nicholas Pomepuy 讨论(link:http://nicolaspomepuy.fr/blur-effect-for-android-design/) 的想法,我们使用子采样和 渲染脚本(link:http://developer.android.com/guide/topics/renderscript/compute.html) 进行快速绘制,当初始化 blurring view 的私有画布 mBlurringCanvas 后,子采样就已经完成了。

  • int scaledWidth = mBlurredView.getWidth() / DOWNSAMPLE_FACTOR;
  • int scaledHeight = mBlurredView.getHeight() / DOWNSAMPLE_FACTOR;
  • mBitmapToBlur = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
  • mBlurringCanvas = new Canvas(mBitmapToBlur);

通过 mBlurringCanvas 的 建立与恰当的渲染脚本初始化,重绘时的 blur() 方法如下:

  • mBlurInput.copyFrom(mBitmapToBlur);
  • mBlurScript.setInput(mBlurInput);
  • mBlurScript.forEach(mBlurOutput);
  • mBlurOutput.copyTo(mBlurredBitmap);

此时 mBlurredBitmap 已准备好,剩下的就是使用适当的变换和缩放,在 blurring view 自己的画布上重绘视图。

实现细节

完整实现 blurring view 时,我们需要注意几个技术点:

一:我们发现缩放因子 8,模糊半径 15 很好地满足我们的目标,但满足你需求的参数可能是不同的。

二:在模糊的 bitmap 边缘会遇到一些渲染脚本效果,我们将缩放的宽度和高度进行了圆角化,直到最近的 4 的倍数。

  • // The rounding-off here is for suppressing RenderScript artifacts at the edge.
  • scaledWidth = scaledWidth - (scaledWidth % 4) + 4;
  • scaledHeight = scaledHeight - (scaledHeight % 4) + 4;

三:为了保证更好的表现效果,我们新建两个 bitmap 对象——mBitmapToBlur 和 mBlurredBitmap ,

mBitmapToBlur 位于私有画布 mBlurringCanvas 之下, mBlurredBitmap 仅当 blurred view 的大小变化时才重新建立他们;

同样地当 blurred view 的大小改变时,我们才创建渲染脚本对象 mBlurInput 和 mBlurOutput。

四:我们以 with PorterDuff.Mode.OVERLAY 模式绘制一个白色半透明的层,它处在被模糊的的图片上层。用来处理设计需求中的淡化。

最后,因为 RenderScript(渲染脚本)至少在 API 17 上才可用,我们需要降低旧版本的安卓,糟糕的是, Nicholas Pomepuy 帖子(link:http://nicolaspomepuy.fr/blur-effect-for-android-design/) 中提到的 Java bitmap 的模糊方法,当恰当地预渲染缓存副本时,对于实时渲染不够迅速,我们所做的是使用一个半透明的 view 作为回调。(更新于 2015 年 3 月 23 日:通过使用 RenderScript 库(link:http://android-developers.blogspot.ca/2013/09/renderscript-in-android-support-library.html) ,我的解决方法能在更低版本的 API 中运行。下面提及的库和 Demo 都更新了,非常感谢 GitHub 上的小伙伴 panzerdev(link:https://github.com/panzerdev) 告诉我这一点)

优点和缺点

我们喜欢这个 view 的绘制方法,因为它可以实时模糊并且容易使用,使得 blurred view 的内容,也在 blurring view 和 blurred view 中间保证了灵活性,最重要的是,它满足了我们的需求

这个方法确实使得 blurring view 与适当协同变换的 blurred view 保持了私有联系,相关地,模糊视图必须不能是 blurred view 的子类,否则会因为互相调用造成堆栈溢出。简单有效处理此限制的方法是要保证模糊视图与 blurred view 在同级,并且 Z 轴次序上 blurred view 在 blurring view 之前。

另一点需要注意的限制是,由于与 矢量图形和文本 有关,我们默认的 bitmap 削减采样表现效果不是很好。

库文件和示例

你可以在我们的安卓 APP 上看到解决方法,我们也把开源的库文件连同一个示例分享到了 github(link:https://github.com/500px/500px-android-blur) ,它能够展示内容变换、动画和视图变换。

城东书院 www.cdsy.xyz
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐