教你快速实现Android动态模糊效果

前言

雅虎天气的界面上滑的时候背景图片会跟着移动,最重要的是背景图片会根据手指上下移动的距离来进行不同程度的模糊,感觉甚为惊奇,毕竟大家都知道,在Android平台上进行模糊渲染是一个相当耗CPU也相当耗时的操作,一旦处理不好,卡顿是在所难免的。

一般来说,考虑到效率,渲染一张图片最好的方法是使用OpenGL,其次是使用C++/C,使用Java代码是最慢的。但是Android推出RenderScript之后,我们就有了新的选择,测试表明,使用RenderScript的渲染效率和使用C/C++不相上下,但是使用RenderScript却比使用JNI简单地多!同时,Android团队提供了RenderScript的支持库,使得在低版本的Android平台上也能使用。

不过在使用RenderScript之前,对于模糊一张图片,需要注意的是,我们应该尽量不要使用原尺寸分辨率的图片,最好将图片缩小比例,这小渲染的效率要高一些。

动态模糊的实现

如何使用RenderScript来模糊一张图片呢?废话不多说,先上核心代码:

public class BlurBitmap { /** * 图片缩放比例 */ private static final float BITMAP_SCALE = 0.4f; /** * 最大模糊度(在0.0到25.0之间) */ private static final float BLUR_RADIUS = 25f; /** * 模糊图片的具体方法 * * @param context 上下文对象 * @param image 需要模糊的图片 * @return 模糊处理后的图片 */ public static Bitmap blur(Context context, Bitmap image) { // 计算图片缩小后的长宽 int width = Math.round(image.getWidth() * BITMAP_SCALE); int height = Math.round(image.getHeight() * BITMAP_SCALE); // 将缩小后的图片做为预渲染的图片。 Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false); // 创建一张渲染后的输出图片。 Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap); // 创建RenderScript内核对象 RenderScript rs = RenderScript.create(context); // 创建一个模糊效果的RenderScript的工具对象 ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); // 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间。 // 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去。 Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap); Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap); // 设置渲染的模糊程度, 25f是最大模糊度 blurScript.setRadius(BLUR_RADIUS); // 设置blurScript对象的输入内存 blurScript.setInput(tmpIn); // 将输出数据保存到输出内存中 blurScript.forEach(tmpOut); // 将数据填充到Allocation中 tmpOut.copyTo(outputBitmap); return outputBitmap; } }

完成上面的代码后,需要在app的gradle文件中添加如下的支持:

defaultConfig { ...... renderscriptTargetApi 19 renderscriptSupportModeEnabled true }

代码做了简单的注释以帮助理解,如果需要详细了解,可以查阅官方文档

然后,我们可以看一下模糊前和模糊后的效果对比:

将图片模糊后,接下来要考虑的是怎么实现动态模糊效,有一点需要注意的是,即使我们使用了RenderScript这种高效的渲染方式,但是在实际测试中,渲染一张500*700分辨率的PNG格式图片,在我的Pro 6手机上,仍然需要50ms左右的时间,显然如果使用上面的代码进行实时渲染的话,会造成界面严重的卡顿。

既然实时渲染这条路走不通,那么就需要我们另辟蹊径了,我这里可以提供一种方法:先将图片进行最大程度的模糊处理,再将原图放置在模糊后的图片上面,通过不断改变原图的透明度(Alpha值)来实现动态模糊效果。

简单的代码如下:

public class MainActivity extends AppCompatActivity { /** * 原始图片控件 */ private ImageView mOriginImg; /** * 模糊后的图片控件 */ private ImageView mBluredImage; /** * 进度条SeekBar */ private SeekBar mSeekBar; /** * 显示进度的文字 */ private TextView mProgressTv; /** * 透明度 */ private int mAlpha; /** * 原始图片 */ private Bitmap mTempBitmap; /** * 模糊后的图片 */ private Bitmap mFinalBitmap; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化视图 initViews(); // 获取图片 mTempBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dayu); mFinalBitmap = BlurBitmap.blur(this, mTempBitmap); // 填充模糊后的图像和原图 mBluredImage.setImageBitmap(mFinalBitmap); mOriginImg.setImageBitmap(mTempBitmap); // 处理seekbar滑动事件 setSeekBar(); } /** * 初始化视图 */ private void initViews() { mBluredImage = (ImageView) findViewById(R.id.activity_main_blured_img); mOriginImg = (ImageView) findViewById(R.id.activity_main_origin_img); mSeekBar = (SeekBar) findViewById(R.id.activity_main_seekbar); mProgressTv = (TextView) findViewById(R.id.activity_main_progress_tv); } /** * 处理seekbar滑动事件 */ private void setSeekBar() { mSeekBar.setMax(100); mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { mAlpha = progress; mOriginImg.setAlpha((int) (255 - mAlpha * 2.55)); mProgressTv.setText(String.valueOf(mAlpha)); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); } }

xml布局文件代码如下:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:layout_width="match_parent" android:layout_weight="1" android:layout_height="0dp"> <ImageView android:id="@+id/activity_main_blured_img" android:scaleType="centerCrop" android:src="@drawable/dayu" android:layout_width="match_parent" android:layout_height="match_parent"/> <ImageView android:id="@+id/activity_main_origin_img" android:scaleType="centerCrop" android:layout_width="match_parent" android:layout_height="match_parent"/> </FrameLayout> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="80dp"> <SeekBar android:layout_marginTop="@dimen/activity_vertical_margin" android:id="@+id/activity_main_seekbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="16dp" android:layout_marginRight="16dp"/> <TextView android:id="@+id/activity_main_progress_tv" android:text="0" android:textSize="24sp" android:layout_gravity="center" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> </LinearLayout>

效果如下:

怎么样?是不是很简单的样子?只需要调用模糊处理方法,并在SeekBar的滑动监听里面调用原图像的setAlpha()方法,来实现动态模糊效果。

你以为这样就完了?不不不,我们的目的并不是这么单纯,哦,不对,并不是这么简单。还记得文章开头的时候说了吗?我们的终极目的是要简单地模仿一下雅虎天气的界面效果。

仿雅虎天气界面

有了上面的基础,就可以很容易地模仿雅虎天气的界面效果。简单来说,在上面制作出的效果基础上,有以下两点需要注意的地方:

需要要监听滑动事件,然后再将背景图片调用setTop()方法,将图片向上平移一段距离。
要向上平移图片,还需要手动增加图片的高度,不然图片向上平移后,底部就会有留白。设置图片高度的核心代码如下:

WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); Point point = new Point(); display.getSize(point); // 获取到ImageView的高度 int height = point.y; ViewGroup.LayoutParams params = imageView.getLayoutParams(); params.width = ViewGroup.LayoutParams.MATCH_PARENT; // 将ImageView的高度增加100 params.height = height + 100; // 应用更改设置 imageView.requestLayout();

完成上面两点的内容后,基本就可以模仿出雅虎天气的首页了。

结合第一个例子的demo,效果如下:

总结

以上就是本文的全部内容了,实现后的效果是不是很赞呢?感兴趣的朋友快快自己动手操作起来吧,希望本文对大家开发Android能有所帮助。

时间: 2024-09-25 05:19:55

教你快速实现Android动态模糊效果的相关文章

教你快速实现Android动态模糊效果_Android

前言 雅虎天气的界面上滑的时候背景图片会跟着移动,最重要的是背景图片会根据手指上下移动的距离来进行不同程度的模糊,感觉甚为惊奇,毕竟大家都知道,在Android平台上进行模糊渲染是一个相当耗CPU也相当耗时的操作,一旦处理不好,卡顿是在所难免的. 一般来说,考虑到效率,渲染一张图片最好的方法是使用OpenGL,其次是使用C++/C,使用Java代码是最慢的.但是Android推出RenderScript之后,我们就有了新的选择,测试表明,使用RenderScript的渲染效率和使用C/C++不相

Android 动态高斯模糊效果教程_Android

写在前面 最近一直在做毕设项目的准备工作,考虑到可能要用到一个模糊的效果,所以就学习了一些高斯模糊效果的实现.比较有名的就是 FastBlur 以及它衍生的一些优化方案,还有就是今天要说的RenderScript . 因为这东西是现在需要才去学习的,所以关于一些图像处理和渲染问题就不提了.不过在使用的过程中确实能感受到,虽然不同的方案都能实现相同的模糊效果,但是效率差别真的很大. 本篇文章实现的高斯模糊是根据下面这篇文章学习的,先推荐一下.本文内容与其内容差不多,只是稍微讲的详细一点,并修改了代

巧用第三方快速开发Android App 热门第三方SDK及框架

巧用第三方快速开发Android App 热门第三方SDK及框架 历经大半年的时间,终于是把这门课程给录制出来了,也就在今天,正式在慕课网上上线了 项目地址:巧用第三方快速开发Android App 热门第三方SDK及框架 这这篇博客也是专门来聊聊这门课程有什么不一样,首先,这门课程是比较针对于快速学习,快速上手的同学的,所以这是面向参加工作或者准备参加工作的同学所迫切需要的,因为只有你掌握了这些,对于你实际开发中才是有帮助的,当然,你要是还在校,那也没关系的,学习本身就是一法通万法,但是你们却

一种粗暴快速的Android全屏幕适配方案

本文讲的是一种粗暴快速的Android全屏幕适配方案,由于Android碎片化严重,屏幕适配一直是开发中较为头疼的问题.面对市面上五花八门的屏幕大小与分辨率,Android基于dp与res目录名称来适配的方案已无法满足一次编写全屏幕适配的需求,为了达到最优的视觉效果,开发过程中总是需要花费较多资源进行适配.也有开发者给出了一些自己的解决方案.首先来分析一下一些常见的解决方案的现状: 1. 官方适配方案 – dp.dp是Android开发中特有的一个单位.与px不同,dp是基于屏幕像素密度的一种单

Flash 8.0教程:动态模糊效果

动态|教程 今晚操练了一下flash8,感觉蛮不错滴,我在网上看了很多flash8的特效,可惜很多都不会做,主要是没有思路,刚才练习了一下blur滤镜,自己动手做了一个动态模糊效果,感觉还不错,就是代码写的太简单了些,不过刚刚开始嘛,先扔块砖头,希望能引来高手做出更好的效果,也让我等菜鸟学习一下(我个人期待水波制作教程的出现,哪位来救我啊) 下面是我刚做的,各位先看看,我儿子噢,靓仔的说(请用player8观看,好像是废话) 点击这里下载源文件 代码加注释:场景中的元件名为pic //拖拽mc并

android动态布局之动态加入TextView和ListView的方法

  本文实例讲述了android动态布局之动态加入TextView和ListView的方法.分享给大家供大家参考.具体实现方法如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 6

保护隐私 快速清除Win8动态磁贴个人信息

微软Windows 8开 始屏幕上那些彩色的磁贴不仅仅是各种应用的快捷入口,对于一些含有实时更新信息的应用,它们的动态磁贴可以自动显示实时信息,比如滚动显示邮件.微博更新 内容.图片.股票走向.天气信息.新闻提要等等,可以说,动态磁贴就是这些应用的实时通知窗口.但是,类似邮件.人脉.图片这些应用毕竟涉及到一些私人信 息,如果是在公共场合被一览无余,可不是一件愉快的事情.有什么办法可以轻松地快速清除Win8动态磁贴的全部信息显示呢? 有的朋友说,可以右键点击动态磁贴,从屏幕底端的操作菜单中选择"关

PS教你快速打造酷炫抢眼的逆光场景

  需求方说:"要有光!"于是,便有了光-- 平时浏览一些优秀作品的时候,经常会看到一些光效处理非常棒的作品.有时我们看后会反问自己:"这些使页面看起来高大的光是怎么打上去的呢?今天搜狐同学通过一个案例来教大家快速打造逆光场景.来找属于你的光吧! 当然,这只是本人自己常用的方法,方法是活的,只要能够做出好的效果就行,这个案例也算不得高大上,只希望那些需要光的同学能够从这篇教程里找到属于自己的光. 先来看一下最终的效果: 这是一个天龙全球争霸赛复活赛的专题页面,这里也许有人会有

教您快速解决MindManager安装失败的难题

  MindManager是一款集创造.管理和交流思想于一体的思维导图软件,其可视化的界面和强大的功能便于您及时.有序地组织思维.资源和项目进程.在安装MindManager思维导图时,如果出现安装错误的问题是比较棘手的,在此和您一起分析MindManager安装失败的原因,教您快速解决MindManager安装失败的问题. 问题一:路径太长的问题. 问题描述:error 1320.The specified path is too long C:ProgramDataMindjetMindMa