Android模糊演示样例-RenderScript-附效果图与代码

本文链接    http://blog.csdn.net/xiaodongrush/article/details/31031411

參考链接    Android高级模糊技术    http://stackoverflow.com/questions/14879439/renderscript-via-the-support-library

1. 程序截图

    拖动红色区域,能够显示出清晰的汽车部分。

拖动以下的滑块,能够更改模糊程度。

     

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGlhb2RvbmdydXNo/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" > 
  

2. 程序实现方法

实现思路。用FrameLayout搞了三层,最底下一层是清晰的图片,中间一层是模糊的图片,最上面的一层。是红色区域,这一层是清晰的图片。

	public static class PlaceholderFragment extends Fragment { // 新版android adt-bundle默认在activity中带一个fragment。据说android stdio早就这样了

		private ImageView mOriginIv;

		private ImageView mBlurIv;

		private ImageView mClearIv;

		private SeekBar mRadiusSb;

		public PlaceholderFragment() {
		}

		@Override
		public View onCreateView(LayoutInflater inflater, ViewGroup container,
				Bundle savedInstanceState) {
			View rootView = inflater.inflate(R.layout.fragment_main, container,
					false);
			return rootView;
		}

		@Override
		public void onActivityCreated(Bundle savedInstanceState) {
			super.onActivityCreated(savedInstanceState);
			mOriginIv = (ImageView) getActivity().findViewById(
					R.id.origin_image);
			mBlurIv = (ImageView) getActivity().findViewById(R.id.blur_image);
			mClearIv = (ImageView) getActivity().findViewById(R.id.clear_image);
			mRadiusSb = (SeekBar) getActivity().findViewById(
					R.id.radius_seekbar);
			drawBlurImage(); // 初始化模糊层。
			setSeekBarChangeListen(); // 设置SeekBar回调。滑块位置变化的时候,更新模糊层。
                        // 延迟是为了保证view.getX。view.getWidth 这类方法可以去到数值,这里仅仅是为了初始化,所以延迟运行比較好。

// 假设要是每次可视化的时候。都要读weidht和x,那么可以再在Activity#onWindowFocusChange中调用。
			Runnable runnable = new Runnable() {

				@Override
				public void run() {
					OnMoveListener listener = new OnMoveListener() {

						@Override
						public void onMoved() {
							mOriginIv.buildDrawingCache();
							clear(mOriginIv.getDrawingCache(), mClearIv, 10); // 这是拿到View绘制图像的好办法
						}
					};
					MoveUtils.enableMove(mClearIv, listener);
				}
			};
			mClearIv.postDelayed(runnable, 500);
		}

		private void drawBlurImage() {
			mOriginIv.getViewTreeObserver().addOnPreDrawListener(
					new OnPreDrawListener() {

						@Override
						public boolean onPreDraw() {
							mOriginIv.getViewTreeObserver()
									.removeOnPreDrawListener(this);
							mOriginIv.buildDrawingCache();
							float radius = mRadiusSb.getProgress();
							if (radius < 0.1) { // RenderScript要求radius必须在0和25之间,不能等于
								radius = 0.1f;
							}
							if (radius > 24.9) {
								radius = 24.9f;
							}
							blur(mOriginIv.getDrawingCache(), mBlurIv, radius);
							clear(mOriginIv.getDrawingCache(), mClearIv, 10); // 这里为了显示边框。偷懒了直接用了10px,实际上是5dip。在我的手机galaxy nexus上。1dip=2px,实际上应该换算一下的。
							return true; // 这个是參考文章中要求的。没试过false。
						}
					});
		}

		private void setSeekBarChangeListen() {
			mRadiusSb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

				@Override
				public void onStopTrackingTouch(SeekBar arg0) {
				}

				@Override
				public void onStartTrackingTouch(SeekBar arg0) {
				}

				@Override
				public void onProgressChanged(SeekBar arg0, int arg1,
						boolean arg2) {
					drawBlurImage();
				}
			});
		}

		// 首先依据view的大小,从bkg生成一个剪裁后的图像;然后依据radius,将剪裁后的图像模糊处理;最后将模糊处理的图像设置到view上。
		@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
		private void blur(Bitmap bkg, View view, float radius) {
                       // 剪裁图片的过程
			Bitmap overlay = Bitmap.createBitmap(
					(int) (view.getMeasuredWidth()),
					(int) (view.getMeasuredHeight()), Bitmap.Config.ARGB_8888);
			Canvas canvas = new Canvas(overlay);
			canvas.translate(-view.getX(), -view.getY()); // 这里是设置坐标系原点
			canvas.drawBitmap(bkg, 0, 0, null); // // 这里直接在新的坐标系的原点上绘制图像,假设不设置坐标系的话,相当于在(view.getX(),view.getY)上绘制图像,android向右是x轴正方形,向下时y轴正方向。
                        // 模糊图片的过程
			RenderScript rs = RenderScript.create(getActivity()); // RenderScript要求apilevel 17,这个比較恶心。v8支持包也不是特别好用。真的要搞模糊的话,还是opencv jni来搞吧。
			Allocation overlayAlloc = Allocation.createFromBitmap(rs, overlay);
			ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(rs,
					overlayAlloc.getElement());
			blur.setInput(overlayAlloc);
			blur.setRadius(radius);
			blur.forEach(overlayAlloc);
			overlayAlloc.copyTo(overlay);
                        // 设置图片
			view.setBackground(new BitmapDrawable(getResources(), overlay));
			rs.destroy();
		}

                // 首先依据view的大小,从bkg生成一个剪裁后的图像;然后将剪裁后的图像设置到view上。
		private void clear(Bitmap bkg, ImageView view, int paddingPx) {
			Bitmap overlay = Bitmap.createBitmap(
					(int) (view.getMeasuredWidth() - paddingPx * 2),
					(int) (view.getMeasuredHeight() - paddingPx * 2),
					Bitmap.Config.ARGB_8888);
			Canvas canvas = new Canvas(overlay);
			canvas.translate(-view.getX() - paddingPx, -view.getY() - paddingPx);
			canvas.drawBitmap(bkg, 0, 0, null);
			view.setImageDrawable(new BitmapDrawable(getResources(), overlay));
		}

	}

3. 代码下载

万恶的CSDN上传了代码。好几个小时了还没审核完。。。

http://download.csdn.net/detail/u011267546/7502603     注意代码的minsdk我设置的比較高,是API Level17。没办法。RenderScript的支持库没搞定。

4. 几个问题

RenderScript     尽管有support-v8支持库。可是我搞了会,也没编译成功。

也看到有帖子说在2.3.5上RenderScript有问题的。所以感觉不是特别靠谱,还是jni+opencv自己搞起来比較好。网上opencv相关的模糊算法非常多。

另外假设图像非常大,模糊处理比較耗时。最好是异步进行。

getWidth。getHeight,getLeft的调用时机      onStart、onReusme这些都不行,仅仅能在onWindowFoucsChange。

本文的演示样例是初始化的时候调用。所以能够延迟一会运行,假设要是每次从后台切换到前台,就要调用的话。那么要在onWindowFoucsChange中调用。

使用canvas剪裁bitmap     注意坐标系。android向右是x轴正方形。向下时y轴正方向。

private void clear(Bitmap bkg, ImageView view, int paddingPx) {
			Bitmap overlay = Bitmap.createBitmap(
					(int) (view.getMeasuredWidth() - paddingPx * 2),
					(int) (view.getMeasuredHeight() - paddingPx * 2),
					Bitmap.Config.ARGB_8888);
			Canvas canvas = new Canvas(overlay);
			canvas.translate(-view.getX() - paddingPx, -view.getY() - paddingPx);
			canvas.drawBitmap(bkg, 0, 0, null);
			view.setImageDrawable(new BitmapDrawable(getResources(), overlay));
		}

获取图片绘制缓存

mOriginIv.buildDrawingCache();
clear(mOriginIv.getDrawingCache(), mClearIv, 10);

让View能够拖动

写了一个简单的方法,通过View的Tag+onTouchEvent,实现View能够拖动。

package com.example.blurtest;

import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class MoveUtils {
	private static final int STATE_IDLE = 0;
	private static final int STATE_MOVING = 1;
	private static final int MIN_GAP = 5;

	private static class Info {
		public int state = STATE_IDLE;
		public float lastX = -1;
		public float lastY = -1;
		public OnMoveListener listener;
	}

	private static Info getInfo(View view) {
		if (view.getTag() == null) {
			view.setTag(new Info());
		}
		return (Info) (view.getTag());
	}

	private static void tryToMove(View view, MotionEvent ev) {
		Info info = getInfo(view);
		if (info.state != STATE_MOVING) {
			return;
		}
		float x = ev.getX() - info.lastX;
		float y = ev.getY() - info.lastY;
		if (Math.abs(x) < MIN_GAP && Math.abs(y) < MIN_GAP) {
			return;
		}
		view.setX(view.getX() + x);
		view.setY(view.getY() + y);
		view.invalidate();
		info.listener.onMoved();
	}

	public static void enableMove(View target, OnMoveListener listener) {
		Info info = new Info();
		info.listener = listener;
		target.setTag(info);
		target.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View view, MotionEvent ev) {
				Info info = getInfo(view);
				int action = ev.getAction() & MotionEvent.ACTION_MASK;
				switch (action) {
				case MotionEvent.ACTION_DOWN:
					info.state = STATE_MOVING;
					info.lastX = ev.getX();
					info.lastY = ev.getY();
					view.setTag(info);
					break;
				case MotionEvent.ACTION_MOVE:
					tryToMove(view, ev);
					break;
				case MotionEvent.ACTION_UP:
					info.state = STATE_IDLE;
					info.lastX = ev.getX();
					info.lastY = ev.getY();
					view.setTag(info);
				default:
					break;
				}
				return true;
			}
		});
	}

	public static interface OnMoveListener {
		public void onMoved();
	}
}
时间: 2024-10-29 19:09:44

Android模糊演示样例-RenderScript-附效果图与代码的相关文章

【COCOS2D-HTML5 开发之三】演示样例项目附源代码及执行的GIF效果图

本站文章均为李华明Himi原创,转载务必在明显处注明:(作者新浪微博:@李华明Himi) 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/cocos2d-html5/1528.html ? 点击订阅 ? 本博客最新动态!及时将最新博文通知您! Cocos2dx html5开发,对于用过2d Or -x的童鞋来说非常easy,Himi这里也没有必要去再跟同学们具体的教学一遍. 所以Himi简单做了一个项目,供给大家參考,源代码下载地址及GIF截图在文章

JDBC连接MySQL数据库及演示样例

JDBC是Sun公司制定的一个能够用Java语言连接数据库的技术. 一.JDBC基础知识         JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,能够为多种关系数据库提供统一訪问,它由一组用Java语言编写的类和接口组成.JDBC为数据库开发者提供了一个标准的API,据此能够构建更高级的工具和接口,使数据库开发者能够用纯 Java API 编写数据库应用程序,而且可跨平台执行,而且不受数据库供应商的限制.

Python Web框架Tornado的异步处理代码演示样例

1. What is Tornado Tornado是一个轻量级但高性能的Python web框架,与还有一个流行的Python web框架Django相比.tornado不提供操作数据库的ORM接口及严格的MVC开发模式,但能够提供主要的web server功能.故它是轻量级的:它借助non-blocking and event-driven的I/O模型(epoll或kqueue)实现了一套异步网络库,故它是高性能的. Tornado的轻量级+高性能特性使得它特别适用于提供web api的场合

10分钟理解Android数据库的创建与使用(附具体解释和演示样例代码)

1.Android数据库简单介绍. Android系统的framework层集成了Sqlite3数据库.我们知道Sqlite3是一种轻量级的高效存储的数据库. Sqlite数据库具有以下长处: (1)零配置,无需安装和配置: (2)储存在单一磁盘文件里的一个完整的数据库. (3)数据库文件能够在不同字节顺序的机器间自由共享: (4)支持数据大小至2TB: (5)足够小.全部源码大致3万行C代码.250KB: (6)比眼下流行的大多数数据库的操作要快. (7)开源. 2.Sqlite 基本操作语句

android listview综合使用演示样例_结合数据库操作和listitem单击长按等事件处理

本演示样例说明: 1.自己定义listview条目样式,自己定义listview显示列数的多少,灵活与数据库中字段绑定. 2.实现对DB的增删改查,而且操作后listview自己主动刷新. 3.响应用户操作点击事件,演示样例中展示单击时取出主键Id和其它内容. 4.响应用户操作长按事件,演示样例中展示长按时依据主键Id来编辑和删除数据. 5.表现层与数据处理层分开,不依赖于cursor(使用cursor不易表现和业务分离),支持接口编程. 6.使用数据库处理框架AHibernate灵活操作sql

Android线程池(二)——ThreadPoolExecutor及其拒绝策略RejectedExecutionHandler使用演示样例

MainActivity例如以下: package cc.vv; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import android.os.Bundle; import android.app.Activity; /** * Demo描写叙述: * 线程池(Threa

Android平台调用Web Service:演示样例

近期在学习Android,随着移动设备的流行,当软件走上商业化的道路.为了争夺市场,肯定须要支持Android的,所以開始接触了Android,只是仅仅了解皮毛就好,由于我们要做管理者嘛.懂点Android.管理起来easy些. Android学起来也简单,封装的更好了,一个个的控件,像是又回到了VB的赶脚. 以下将通过一个演示样例解说怎样在Android平台调用Web Service. 我们使用互联网现成的Webservice.供查询手机号码归属地的Web service,它的WSDL为htt

Android之——多线程下载演示样例

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/46883927 一.概述 说到Android中的文件下载.Android API中明白要求将耗时的操作放到一个子线程中运行,文件的下载无疑是须要耗费时间的.所以要将文件的下载放到子线程中运行. 以下,我们一起来实现一个Android中利用多线程下载文件的小样例. 二.服务端准备 在这个小样例中我下面载有道词典为例.在网上下载有道词典的安装包,在eclipse中新建项目web.将下载

将 Android* x86 NDK 用于 Eclipse* 并移植 NDK 演示样例应用

目标 面向 Eclipse (ADT) 的 Android 插件如今支持基于 NDK 的应用开发. 其可自己主动生成项目和构件文件以及代码存根,并可集成到整个 Android 应用开发中(构建原生库.将库拷贝到项目内的对应 JNI 目录.将应用打包以及生成带有 NDK 代码的终于 APK). 本文将讨论怎样配置 Eclipse 以利用该功能.并示范移植 NDK 应用的演示样例. 配置 Eclipse ADT 插件以配合 NDK 使用 必须先配置 Eclipse ADT 插件指向 NDK 安装路径