1.前言

       项目中有需要点击展示大图的,然而发现手机端的图片展示更多的是黑色背景+图片展示,最多加上个缩放动画。更让强迫症纠结的是:因为android的本身的原因(从nexus到小米魅族),使用activity进行图片展示会有几率看到statusbar下滑消失动画(对的,没看错,有几率),单单是几率两字就让人纠结不已......随萌生出了些本博客代码——dialog+高斯模糊+图片展示的想法。

效果:

录制看着卡,真机上流畅。

2.高斯模糊

       高斯模糊在苹果系统中很常见,然而在android系统中却鲜有闻,很多app对于高斯模糊的态度是能避免就避免的,究其原因很简单——费时,这里大致讲下高斯模糊的原理:假设一张100*100的图片,上边有10000个像素点,每个像素点作为中心点,按照高斯分布的概率算均值,也就是说,每多一个点,计算时间就会增加很多。闲话不叙,上例子:

这是截的原图。然后,以30个像素点为半径进行高斯模糊:

打印了下log,可以看出耗时是:I/need time: 671 .....(高斯模糊采用的是fastblur方法,如果嫌效率一般,可以考虑用jni,据说速度能降低一半,但是,放在这里的,还是不够)

然而图片并不能让我们满意,虽然有点模糊的意思了,但是感觉还是略微有点棱角......

好吧,那就将半径设为60,看看结果如何:

只能说感觉还好吧,但是用了868ms,上一张我个人比较满意的150的高斯模糊:

然而耗时1156ms.

如果以这种速度去处理图片那就很尴尬了,总不能在做相应操作的时候去等个1s多吧,虽然可以把图片处理放在子线程中,不影响主线程对其他任务的处理,然而这并不是一个靠谱的解决方案,所以决定去尝试下图片压缩:处理速度慢的根本原因是因为想像素数量多,如果我进行压缩呢?

嗯 先上个对比图:

看着差别大么?

一个是长宽压缩过,并进行8像素半径高斯模糊的,一个是原图基础上150高斯模糊的,更喜欢哪个?

左边是原图的,右边是压缩的,压缩后的长宽是原来的十六分之一,更让人高兴的是,压缩+高斯模糊全过程持续了3ms......对没错,一个1156 一个3ms。然而唯一比较遗憾的是,android貌似没有局部截图的工具,如果自己获取整个页面再生成bitmap处理,整个生成bitmap在nexus5上就需要接近40ms,所以暂时来说,没想到有什么好的实时高斯模糊的办法。所以,高斯从淡到完全显示用的是原图上边铺上高斯模糊图,然后alpha动画走起

ok,进入今天的正题,高斯模糊+图片显示

3.高斯模糊背景的图片展示

之前难点都讲的差不多了,直接上代码吧:

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;import com.example.angusfine.mywidget.R;/*** Created by AngusFine on 2016/3/22.*/
public class ImagePreviewDialog extends Dialog implements View.OnClickListener{private final int animationTime = 250; //动画时间private Context context;private ImageView targetView; //目标ImageViewprivate View mParentView; //DisplayFrame氛围内的RootViewprivate int[]location = new int[2]; //targetView 屏幕坐标private Bitmap gaussBg; //mParentView高斯的结果private ImageView ivGauss;private ImageView ivShadow;private ImageView ivShow; //targetView展示private View currentView; //dialog对应的Viewprivate int currentW;private int currentH;private int displayH;private Rect rect; //displayframe对应的存储信息private boolean vertical = false;private boolean backable = true;float fY; //动画终点Y坐标float dY;float fX;float dX;/**** @param context* 类中方法调用对应View的绘制顺序,不可修改*/public ImagePreviewDialog(Context context){super(context, R.style.GaussDialog);this.context = context;Log.i("DecordhashCode",String.valueOf(((Activity)context).getWindow().getDecorView().hashCode()));ViewGroup decor = (ViewGroup) ((Activity)context).getWindow().getDecorView();Log.i("DecordhashCoded",String.valueOf(decor.hashCode()));for(int i = 0;i<decor.getChildCount();i++){if(decor.getChildAt(i)instanceof LinearLayout){ViewGroup ll = (ViewGroup)decor.getChildAt(i);for(int j = 0;j<ll.getChildCount();j++){if (ll.getChildAt(j)instanceof FrameLayout){this.mParentView = ll.getChildAt(j);break;}}}}initBg();getStatusBarInfo();}public ImagePreviewDialog setTargetView(ImageView view){((Activity)context).getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);targetView = view;getImageViewInfo();initTargetView();initGaussBitmap();initAnimation();return this;}/*** bg初始化*/private void initBg(){currentView = LayoutInflater.from(getContext()).inflate(R.layout.dialog_gauss_bg_pic,null);setContentView(currentView);ivGauss = (ImageView) currentView.findViewById(R.id.iv_gauss);ivShadow = (ImageView) currentView.findViewById(R.id.iv_shadow);currentView.setOnClickListener(this);}/*** 获取展示View的对应信息*/private void getImageViewInfo(){targetView.getLocationOnScreen(location);currentW = targetView.getMeasuredWidth();currentH = targetView.getMeasuredHeight();}/*** 状态栏信息*/private void getStatusBarInfo(){rect = new Rect();((Activity)context).getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);displayH = ((Activity)context).getWindow().getDecorView().getMeasuredHeight();}/*** 高斯模糊*/private void initGaussBitmap(){gaussBg = convertViewToBitmap(mParentView,mParentView.getWidth(),mParentView.getHeight());gaussBg = zoomImage(gaussBg,mParentView.getMeasuredWidth()/16,mParentView.getMeasuredHeight()/16);gaussBg = gaussBlur(gaussBg,5,true);ivGauss.setImageBitmap(gaussBg);}/*** 加载展示View*/private void initTargetView(){FrameLayout.LayoutParams layoutParams= new FrameLayout.LayoutParams(currentW,currentH);ivShow = new ImageView(context);ivShow.setImageDrawable(targetView.getDrawable());ivShow.setX(location[0]);ivShow.setY(location[1]-rect.top);ivShow.setScaleType(targetView.getScaleType());ivShow.setLayoutParams(layoutParams);((ViewGroup)currentView).addView(ivShow);}private void initAnimation(){float w = targetView.getMeasuredWidth();float h = targetView.getMeasuredHeight();float dw = rect.right - rect.left;final float dh = rect.bottom - rect.top;float ratio = h/w;float dRatio = dh/dw;final float maxRatio;backable = true;ivShadow.setAlpha(0f);if(ratio>dRatio){vertical = true;maxRatio = dh/h;fY = ((maxRatio-1)*h)/2;dY = location[1]-fY;fX = location[0]-dw/2+w/2;}else{maxRatio = dw/w;dY = location[1] - dh/2 +h/2;fX = ((maxRatio-1)*w)/2;dX = location[0]-fX;}final AlphaAnimation alphaAnimation = new AlphaAnimation(0.0f,1.0f);alphaAnimation.setDuration(animationTime);alphaAnimation.setFillAfter(true);ObjectAnimator animator = ObjectAnimator.ofFloat(ivShow,"an",1.0f,maxRatio).setDuration(200);animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float cVal = (Float) animation.getAnimatedValue();float YDRatio = (cVal-1)/(maxRatio-1);float dRatio = 1-YDRatio;if(vertical) {ivShow.setScaleX(cVal);ivShow.setScaleY(cVal);ivShow.setX(location[0] - fX * (YDRatio));ivShow.setY(dY * dRatio + fY-rect.top*dRatio);}else{ivShow.setY(location[1]-rect.top*dRatio-dY*YDRatio);ivShow.setX(dX*dRatio+fX);ivShow.setScaleX(cVal);ivShow.setScaleY(cVal);}ivShadow.setAlpha(YDRatio);}});ivGauss.startAnimation(alphaAnimation);animator.start();}private void backAnimation(){if(!backable)return;backable = false;float w = targetView.getMeasuredWidth();float h = targetView.getMeasuredHeight();float dw = rect.right - rect.left;final float dh = rect.bottom - rect.top;float ratio = h/w;float dRatio = dh/dw;final float maxRatio;if(ratio>dRatio){vertical = true;maxRatio = dh/h;}else{maxRatio = dw/w;fX = ((maxRatio-1)*w)/2;dX = location[0] - fX;}AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f,0f);alphaAnimation.setDuration(animationTime);alphaAnimation.setFillAfter(true);alphaAnimation.setAnimationListener(new Animation.AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationEnd(Animation animation) {ivShow.setVisibility(View.GONE);ImagePreviewDialog.super.dismiss();}@Overridepublic void onAnimationRepeat(Animation animation) {}});ObjectAnimator animator = ObjectAnimator.ofFloat(ivShow,"an",maxRatio,1f).setDuration(animationTime);animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float cVal = (Float) animation.getAnimatedValue();float YDRatio = (cVal-1)/(maxRatio-1);float dRatio = 1-YDRatio;if(vertical) {ivShow.setScaleX(cVal);ivShow.setScaleY(cVal);ivShow.setX(location[0] - fX * (YDRatio));ivShow.setY(dY * dRatio + fY-rect.top*dRatio);}else{ivShow.setY(location[1]-rect.top*dRatio-dY*YDRatio);ivShow.setX(fX+dRatio*dX);ivShow.setScaleX(cVal);ivShow.setScaleY(cVal);}ivShow.setAlpha(YDRatio);}});animator.start();ivGauss.startAnimation(alphaAnimation);ivShadow.startAnimation(alphaAnimation);}@Overridepublic void onBackPressed() {backAnimation();}/*** 图片缩放* @param targetBitmap 目标bitmap* @param newWidth  目标宽度* @param newHeight  目标高度* @return*/private Bitmap zoomImage(Bitmap targetBitmap, double newWidth, double newHeight) {float width = targetBitmap.getWidth();float height = targetBitmap.getHeight();Matrix matrix = new Matrix();float scaleWidth = ((float) newWidth) / width;float scaleHeight = ((float) newHeight) / height;matrix.postScale(scaleWidth, scaleHeight);Bitmap bitmap = Bitmap.createBitmap(targetBitmap, 0, 0, (int) width, (int) height, matrix, true);return bitmap;}/*** View转Bitmap* @param view 目标View* @param bitmapWidth 宽度* @param bitmapHeight 高度* @return*/private Bitmap convertViewToBitmap(View view, int bitmapWidth, int bitmapHeight){Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);view.draw(new Canvas(bitmap));return bitmap;}/*** 高斯模糊* @param sentBitmap 目标bitmap* @param radius 高斯半径* @param canReuseInBitmap  是否原图修改* @return*/private Bitmap gaussBlur(Bitmap sentBitmap, int radius, boolean canReuseInBitmap) {Bitmap bitmap;if (canReuseInBitmap) {bitmap = sentBitmap;} else {bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);}if (radius < 1) {return (null);}int w = bitmap.getWidth();int h = bitmap.getHeight();int[] pix = new int[w * h];bitmap.getPixels(pix, 0, w, 0, 0, w, h);int wm = w - 1;int hm = h - 1;int wh = w * h;int div = radius + radius + 1;int r[] = new int[wh];int g[] = new int[wh];int b[] = new int[wh];int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;int vmin[] = new int[Math.max(w, h)];int divsum = (div + 1) >> 1;divsum *= divsum;int dv[] = new int[256 * divsum];for (i = 0; i < 256 * divsum; i++) {dv[i] = (i / divsum);}yw = yi = 0;int[][] stack = new int[div][3];int stackpointer;int stackstart;int[] sir;int rbs;int r1 = radius + 1;int routsum, goutsum, boutsum;int rinsum, ginsum, binsum;for (y = 0; y < h; y++) {rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;for (i = -radius; i <= radius; i++) {p = pix[yi + Math.min(wm, Math.max(i, 0))];sir = stack[i + radius];sir[0] = (p & 0xff0000) >> 16;sir[1] = (p & 0x00ff00) >> 8;sir[2] = (p & 0x0000ff);rbs = r1 - Math.abs(i);rsum += sir[0] * rbs;gsum += sir[1] * rbs;bsum += sir[2] * rbs;if (i > 0) {rinsum += sir[0];ginsum += sir[1];binsum += sir[2];} else {routsum += sir[0];goutsum += sir[1];boutsum += sir[2];}}stackpointer = radius;for (x = 0; x < w; x++) {r[yi] = dv[rsum];g[yi] = dv[gsum];b[yi] = dv[bsum];rsum -= routsum;gsum -= goutsum;bsum -= boutsum;stackstart = stackpointer - radius + div;sir = stack[stackstart % div];routsum -= sir[0];goutsum -= sir[1];boutsum -= sir[2];if (y == 0) {vmin[x] = Math.min(x + radius + 1, wm);}p = pix[yw + vmin[x]];sir[0] = (p & 0xff0000) >> 16;sir[1] = (p & 0x00ff00) >> 8;sir[2] = (p & 0x0000ff);rinsum += sir[0];ginsum += sir[1];binsum += sir[2];rsum += rinsum;gsum += ginsum;bsum += binsum;stackpointer = (stackpointer + 1) % div;sir = stack[(stackpointer) % div];routsum += sir[0];goutsum += sir[1];boutsum += sir[2];rinsum -= sir[0];ginsum -= sir[1];binsum -= sir[2];yi++;}yw += w;}for (x = 0; x < w; x++) {rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;yp = -radius * w;for (i = -radius; i <= radius; i++) {yi = Math.max(0, yp) + x;sir = stack[i + radius];sir[0] = r[yi];sir[1] = g[yi];sir[2] = b[yi];rbs = r1 - Math.abs(i);rsum += r[yi] * rbs;gsum += g[yi] * rbs;bsum += b[yi] * rbs;if (i > 0) {rinsum += sir[0];ginsum += sir[1];binsum += sir[2];} else {routsum += sir[0];goutsum += sir[1];boutsum += sir[2];}if (i < hm) {yp += w;}}yi = x;stackpointer = radius;for (y = 0; y < h; y++) {pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];rsum -= routsum;gsum -= goutsum;bsum -= boutsum;stackstart = stackpointer - radius + div;sir = stack[stackstart % div];routsum -= sir[0];goutsum -= sir[1];boutsum -= sir[2];if (x == 0) {vmin[y] = Math.min(y + r1, hm) * w;}p = x + vmin[y];sir[0] = r[p];sir[1] = g[p];sir[2] = b[p];rinsum += sir[0];ginsum += sir[1];binsum += sir[2];rsum += rinsum;gsum += ginsum;bsum += binsum;stackpointer = (stackpointer + 1) % div;sir = stack[stackpointer];routsum += sir[0];goutsum += sir[1];boutsum += sir[2];rinsum -= sir[0];ginsum -= sir[1];binsum -= sir[2];yi += w;}}bitmap.setPixels(pix, 0, w, 0, 0, w, h);return (bitmap);}@Overridepublic void onClick(View v) {backAnimation();}
}

然后布局代码:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><ImageViewandroid:id="@+id/iv_gauss"android:layout_width="match_parent"android:layout_height="match_parent"/><ImageViewandroid:id="@+id/iv_shadow"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/transparent_gray"/></FrameLayout>

以及style设置:

<style name="GaussDialog"><item name="android:windowBackground">@color/transparent</item><item name="android:windowNoTitle">true</item><item name="android:windowFullscreen">false</item><item name="android:windowIsTranslucent">true</item><item name="android:backgroundDimEnabled">false</item><item name="android:background">#00000000</item></style>

色值设置:

<color name="transparent_gray">#88000000</color>

嗯,使用方法很简单,只要两行代码:

imagePreviewDialog = new ImagePreviewDialog(this);
imagePreviewDialog.setTargetView(iv).show();

(第二行代码,需要在目标View显示后进行调用,否则获得的getmeasuredwidth以及高度会为0)

ok,这就完事了

其实这个版本很不完善,当时代码写的很急,后来也因为各种原因没在进行完善,功能上可以做不少的优化及扩展,以后有空再说吧
转帖请标明


高斯模糊加图片展示(仿ipad qq图片点击展示)相关推荐

  1. Android 仿微信 QQ 图片裁剪,赶紧收藏起来!

    在正文之前,先公布下周三的送书中奖名单,点赞前15名为: 码不停蹄 િ?ી.zdxོ.gaolhjy.C.Aiden_ryan.进进.WhenSun .明($?.啊鑫.久伴.街 景 -.小石头.纸.冯 ...

  2. 仿微信 QQ 图片选择器

    iOS8以后苹果推出了 Photos.Framework来管理用户相册等多媒体资源,笔者抱着学习的态度仿写了一个多图片选择器,利用 Photos.Framework 来获取相册里的相片视频. CYPh ...

  3. fullcalendar内容如何默认展示一条其他的点击展示_LinkedIn广告全指南:如何从零开始成为Linkedin广告高手?...

    据统计,LinkedIn拥有超过6.45亿专业人士,是B2B市场重要的社交渠道.事实上,80%的社交媒体B2B营销线索都来自LinkedIn,92%的B2B营销人员使用这个平台进行营销推广.接下来,你 ...

  4. 圆形进度条(包括仿QQ图片加载进度图)

    原文:圆形进度条(包括仿QQ图片加载进度图) 源代码下载地址:http://www.zuidaima.com/share/1581277496822784.htm 以前找到的自定义圆形进度条

  5. android从九宫格全屏预览,仿微信朋友圈展示图片的九宫格图片展示控件,支持点击图片全屏预览大图...

    AssNineGridView 仿微信朋友圈展示图片的九宫格图片展示控件,支持点击图片全屏预览大图(可自定义). 写在前面 这是一个九宫格控件,本来是很久之前就写好了,现在才开源出来,也是看了很多优秀 ...

  6. android qq底部图片选择器,Android 高仿QQ图片选择器

    当做一款APP,需要选择本地图片时,首先考虑的无疑是系统相册,但是Android手机五花八门,再者手机像素的提升,大图无法返回等异常因数,导致适配机型比较困难,微信.QQ都相继的在自己的APP里集成了 ...

  7. Android笔记之(图片高斯+Glide实现微信图片加载策略+仿微信进度条)

    很久以前就想自己实现一下仿微信图片加载的那种策略了,先加载一张模糊的图片,然后再加载清晰大图,今天研究了一下,不过要是Glide支持进度条显示就好了,不得不说Glide很强大, 不啰嗦了,直接上代码了 ...

  8. JS 点击弹出图片/ 仿QQ商城点击左右滚动幻灯片/ 相册模块,点击弹出图片,并左右滚动幻灯片...

    1, 点击弹出图片 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://w ...

  9. android动画超出圆角,Android关于Glide的使用(高斯模糊、加载监听、圆角图片)

    高斯模糊.加载监听.圆角图片这些相信大家都很熟悉,那如何实现这些效果,请大家参考本文进行学习. 1.引用 compile 'com.github.bumptech.glide:glide:3.7.0' ...

最新文章

  1. python 笔记:if __name__==‘main’
  2. CentOS 5.2+Raid 0+LVM+ISCSI配置详解
  3. 岁月在变迁,彼此在成长。而我在流浪
  4. H.264中POC类型之探讨
  5. java 快捷工具,如何清理不需要的引用
  6. php裁剪图片白边,php生成缩略图填充白边(等比缩略图方案)_PHP
  7. Vue同级组件数据传递
  8. Java Hamcrest学习
  9. 1、RFID标签介绍
  10. php 七牛云 视频加水印
  11. 13号线ab线规划图_北京地铁13号线拆分成这样了(附图)
  12. 计算机金融学校排名2015,金融学院2015级各专业排名情况统计表
  13. C 龟兔赛跑题目:T分钟后乌龟和兔子谁跑得快?
  14. 员工计算机耗材管理,八大秘籍教你精细化管理科室耗材!
  15. 微信小程序使用后台播放器播放音乐
  16. 线性回归实战---Abalone鲍鱼年龄预测
  17. 说说大型网站可伸缩性架构的设计原理
  18. 关系数据库、关系代数和关系运算
  19. MapX和MapXtreme区别
  20. 【VINS-Mono】Estimator::initialStructure

热门文章

  1. [docker]十、docker swarm是什么?以及创建docker swarm
  2. Python实现视频运动目标检测——帧差法
  3. python爬快手个人介绍个性_2018最火快手主页介绍个性签名 独一无二的快手主页介绍句子...
  4. 【codeforces 709D】Recover the String
  5. 网络爬虫快速入门(二)
  6. 用CSS巧控制段落缩进段落首字下沉
  7. 小白,你要的Java抽象类,操碎了心!
  8. IDEA下载与安装(2020)
  9. Linux安装及管理程序 配置yum本地仓库
  10. fxmarket:9月23日恒指、沪深300、上证行情分析