本文链接    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" alt=""> 
  

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();
}
}

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

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

    本站文章均为李华明Himi原创,转载务必在明显处注明:(作者新浪微博:@李华明Himi) 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/cocos2d- ...

  2. Android popupwindow 演示样例程序一

    经过多番測试实践,实现了popupwindow 弹出在指定控件的下方.代码上有凝视.有须要注意的地方.popupwindow 有自已的布局,里面控件的监听实现都有.接下来看代码实现. 项目资源下载:点 ...

  3. 构造Scala开发环境并创建ApiDemos演示样例项目

    从2011年開始写Android ApiDemos 以来.Android的版本号也更新了非常多,眼下的版本号已经是4.04. ApiDemos中的样例也添加了不少,有必要更新Android ApiDe ...

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

    JDBC是Sun公司制定的一个能够用Java语言连接数据库的技术. 一.JDBC基础知识         JDBC(Java Data Base Connectivity,java数据库连接)是一种用 ...

  5. 01_MUI之Boilerplate中:HTML5演示样例,动态组件,自己定义字体演示样例,自己定义字体演示样例,图标字体演示样例

     1安装HBuilder5.0.0,安装后的界面截图例如以下: 2 依照https://www.muicss.com/docs/v1/css-js/boilerplate-html中的说明,创建上 ...

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

    1. What is Tornado Tornado是一个轻量级但高性能的Python web框架,与还有一个流行的Python web框架Django相比.tornado不提供操作数据库的ORM接口 ...

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

    1.Android数据库简单介绍. Android系统的framework层集成了Sqlite3数据库.我们知道Sqlite3是一种轻量级的高效存储的数据库. Sqlite数据库具有以下长处: (1) ...

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

    本演示样例说明: 1.自己定义listview条目样式,自己定义listview显示列数的多少,灵活与数据库中字段绑定. 2.实现对DB的增删改查,而且操作后listview自己主动刷新. 3.响应用 ...

  9. [Android]RecyclerView的简单演示样例

    去年google的IO上就展示了一个新的ListView.它就是RecyclerView. 下面是官方的说明,我英语能力有限,只是我大概这么理解:RecyclerView会比ListView更具有拓展 ...

随机推荐

  1. windows命令启动mysql

    找到mysql的安装位置,进入bin目录 dos输入  mysql -h localhost -uroot -p   ,在输入密码

  2. tmpfs文件系统

    centos 7测试OK 创建挂载点,挂载 mkdir -p /run/testdirmount -nt tmpfs -o size=500m,mode=755 tmpfs /run/testdir

  3. python毫秒级sleep

    Python中的sleep函数可以传小数进去,然后就可以进行毫秒级的延时了 # 例1:循环输出休眠1秒 import time i = 1 while i = 3: print i # 输出i i + ...

  4. thinkphp下实现ajax无刷新分页

    1.前言 作为一名php程序员,我们开发网站主要就是为了客户从客户端进行体验,在这里,thinkphp框架自带的分页类是每次翻页都要刷新一下整个页面,这种翻页的用户体验显然是不太理想的,我们希望每次翻 ...

  5. PAT L3-002. 堆栈

    树状数组,二分. 一堆数字,可以删除栈顶,压入数字,求中位数,可以线段树,也可以树状数组上二分. #include<map> #include<set> #include< ...

  6. python 理解高阶函数

    高阶函数 高阶函数英文叫Higher-order function.什么是高阶函数? 变量可以指向函数 以Python内置的求绝对值的函数abs()为例,调用abs(): >>> a ...

  7. Spring Cloud Eureka 总结

    写在前面的话(给自己) 为了巩固自身学习,从今天(2019.01.08),每天晚上开始总结SpringCloud的相关学习,用于自我勉励,自我积累与人生总结. 总结2018年的我,心态较之从前浮躁,杂 ...

  8. Mindjet Mindmanager复制文件打不开

    概述 使用Mindjet软件画思维导图,保存后得到一个后缀为mmap的文件.复制到一个新的位置,却发现新的文件打不开,导致Mindjet崩溃.这里提供一个解决方案. 解决方案 复制的文件打不开 先打开 ...

  9. 洛谷——P1724 东风谷早苗

    P1724 东风谷早苗 题目描述 在幻想乡,东风谷早苗是以高达控闻名的高中生宅巫女.某一天,早苗终于入手了最新款的钢达姆模型.作为最新的钢达姆,当然有了与以往不同的功能了,那就是它能够自动行走,厉害吧 ...

  10. 【jzyzoj】【p1320 patrol】 巡逻(网络流最小割例题)

    描述 Description FJ有个农场,其中有n块土地,由m条边连起来.FJ的养牛场在土地1,在土地n有个新开张的雪糕店.Bessie经常偷偷溜到雪糕店,当Bessie去的时候,FJ就要跟上她.但 ...