zoukankan      html  css  js  c++  java
  • Android模糊演示样例-RenderScript-附效果图与代码

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

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

    1. 程序截图

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

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

                 

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

        

  • 相关阅读:
    「七天自制PHP框架」第四天:模型关联
    「七天自制PHP框架」第三天:PHP实现的设计模式
    「七天自制PHP框架」第二天:模型与数据库
    一个例子简要说明include和require的区别
    解读Laravel,看PHP如何实现Facade?
    Laravel是怎么实现autoload的?
    Laravel表单提交
    Laravel的console使用方法
    PHP控制反转(IOC)和依赖注入(DI)
    PHP解耦的三重境界(浅谈服务容器)
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/7286880.html
Copyright © 2011-2022 走看看