這幾天項目中需要模仿一下iOS版本的微博菜單彈出界面,如下圖:
用微博的同學都知道這個效果吧瘤载,這篇文章先實現(xiàn)模糊效果,進入卖擅、退出動畫后面文章分析鸣奔;
一、說一下實現(xiàn)思路惩阶,很簡單的:
1挎狸、截圖:就是獲取我們app得截圖
獲取我們Activity得根view即DecorView,關于DecorView断楷,sdk里面是這么說明的:
Retrieve?the?top-level?window?decor?view?(containing?the?standard?window?frame/decorations?and?the?client's?content?inside?of?that),?which?can?be?added?as?a?window?to?the?window?manager.
就是說獲取最頂層的window锨匆,可以添加到window manager里面;
拿到view之后可以調用view的getDrawingCache方法獲取bitmap截圖冬筒;
2恐锣、對圖片做高斯模糊;
高斯模糊在Photoshop里面用的比較多舞痰,可以用來去痘痘土榴。
大致原理是:對指定像素和其周圍像素進行加權平均來得到最終結果,使用高斯分布作為濾波器匀奏。
這兒可以了解詳細的算法原理:http://www.ruanyifeng.com/blog/2012/11/gaussian_blur.html
二鞭衩、代碼實現(xiàn):
代碼比較簡單,我自己加了注釋貼出來了:
privatevoidapplyBlur()?{
View?view?=?getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache(true);
/**
*?獲取當前窗口快照娃善,相當于截屏
*/
Bitmap?bmp1?=?view.getDrawingCache();
intheight?=?getOtherHeight();
/**
*?除去狀態(tài)欄和標題欄
*/
Bitmap?bmp2?=?Bitmap.createBitmap(bmp1,0,?height,bmp1.getWidth(),?bmp1.getHeight()?-?height);
blur(bmp2,?text);
}
@SuppressLint("NewApi")
privatevoidblur(Bitmap?bkg,?View?view)?{
longstartMs?=?System.currentTimeMillis();
floatscaleFactor?=8;//圖片縮放比例论衍;
floatradius?=20;//模糊程度
Bitmap?overlay?=?Bitmap.createBitmap(
(int)?(view.getMeasuredWidth()?/?scaleFactor),
(int)?(view.getMeasuredHeight()?/?scaleFactor),
Bitmap.Config.ARGB_8888);
Canvas?canvas?=newCanvas(overlay);
canvas.translate(-view.getLeft()?/?scaleFactor,?-view.getTop()/?scaleFactor);
canvas.scale(1/?scaleFactor,1/?scaleFactor);
Paint?paint?=newPaint();
paint.setFlags(Paint.FILTER_BITMAP_FLAG);
canvas.drawBitmap(bkg,0,0,?paint);
overlay?=?FastBlur.doBlur(overlay,?(int)?radius,true);
view.setBackground(newBitmapDrawable(getResources(),?overlay));
/**
*?打印高斯模糊處理時間,如果時間大約16ms聚磺,用戶就能感到到卡頓坯台,時間越長卡頓越明顯,如果對模糊完圖片要求不高瘫寝,可是將scaleFactor設置大一些蜒蕾。
*/
Log.i("jerome","blur?time:"+?(System.currentTimeMillis()?-?startMs));
}
/**
*?獲取系統(tǒng)狀態(tài)欄和軟件標題欄稠炬,部分軟件沒有標題欄,看自己軟件的配置咪啡;
*?@return
*/
privateintgetOtherHeight()?{
Rect?frame?=newRect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
intstatusBarHeight?=?frame.top;
intcontentTop?=?getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();
inttitleBarHeight?=?contentTop?-?statusBarHeight;
returnstatusBarHeight?+?titleBarHeight;
}
我這里用了外國開源項目中的一個Java算法首启,地址:https://github.com/paveldudka/blurring
packagecom.jerome.popdemo;
importandroid.graphics.Bitmap;
/**
*?Created?by?paveld?on?3/6/14.
*/
publicclassFastBlur?{
publicstaticBitmap?doBlur(Bitmap?sentBitmap,intradius,
booleancanReuseInBitmap)?{
Bitmap?bitmap;
if(canReuseInBitmap)?{
bitmap?=?sentBitmap;
}else{
bitmap?=?sentBitmap.copy(sentBitmap.getConfig(),true);
}
if(radius?<1)?{
return(null);
}
intw?=?bitmap.getWidth();
inth?=?bitmap.getHeight();
int[]?pix?=newint[w?*?h];
bitmap.getPixels(pix,0,?w,0,0,?w,?h);
intwm?=?w?-1;
inthm?=?h?-1;
intwh?=?w?*?h;
intdiv?=?radius?+?radius?+1;
intr[]?=newint[wh];
intg[]?=newint[wh];
intb[]?=newint[wh];
intrsum,?gsum,?bsum,?x,?y,?i,?p,?yp,?yi,?yw;
intvmin[]?=newint[Math.max(w,?h)];
intdivsum?=?(div?+1)?>>1;
divsum?*=?divsum;
intdv[]?=newint[256*?divsum];
for(i?=0;?i?<256*?divsum;?i++)?{
dv[i]?=?(i?/?divsum);
}
yw?=?yi?=0;
int[][]?stack?=newint[div][3];
intstackpointer;
intstackstart;
int[]?sir;
intrbs;
intr1?=?radius?+1;
introutsum,?goutsum,?boutsum;
intrinsum,?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++)?{
//?Preserve?alpha?channel:?(?0xff000000?&?pix[yi]?)
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);
}
}
如果用C/C++實現(xiàn)jni調用,效果會高一些撤摸,可以參考:https://github.com/qiujuer/ImageBlurring/blob/master/README-ZH.md
/*************************************************
Copyright:??Copyright?QIUJUER?2013.
Author:?????Qiujuer
Date:???????2014-04-18
Description:實現(xiàn)圖片模糊處理
**************************************************/
#include
#define?ABS(a)?((a)<(0)?(-a):(a))
#define?MAX(a,b)?((a)>(b)?(a):(b))
#define?MIN(a,b)?((a)<(b)?(a):(b))
/*************************************************
Function:???????StackBlur(堆棧模糊)
Description:????使用堆棧方式進行圖片像素模糊處理
Calls:??????????malloc
Table?Accessed:?NULL
Table?Updated:??NULL
Input:??????????像素點集合毅桃,圖片寬,圖片高准夷,模糊半徑
Output:?????????返回模糊后的像素點集合
Return:?????????返回模糊后的像素點集合
Others:?????????NULL
*************************************************/
staticint*?StackBlur(int*?pix,intw,inth,intradius)?{
intwm?=?w?-1;
inthm?=?h?-1;
intwh?=?w?*?h;
intdiv?=?radius?+?radius?+1;
int*r?=?(int*)malloc(wh?*?sizeof(int));
int*g?=?(int*)malloc(wh?*?sizeof(int));
int*b?=?(int*)malloc(wh?*?sizeof(int));
intrsum,?gsum,?bsum,?x,?y,?i,?p,?yp,?yi,?yw;
int*vmin?=?(int*)malloc(MAX(w,h)?*?sizeof(int));
intdivsum?=?(div?+1)?>>1;
divsum?*=?divsum;
int*dv?=?(int*)malloc(256*?divsum?*?sizeof(int));
for(i?=0;?i?<256*?divsum;?i++)?{
dv[i]?=?(i?/?divsum);
}
yw?=?yi?=0;
int(*stack)[3]?=?(int(*)[3])malloc(div?*3*?sizeof(int));
intstackpointer;
intstackstart;
int*sir;
intrbs;
intr1?=?radius?+1;
introutsum,?goutsum,?boutsum;
intrinsum,?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?+?(MIN(wm,?MAX(i,0)))];
sir?=?stack[i?+?radius];
sir[0]?=?(p?&0xff0000)?>>16;
sir[1]?=?(p?&0x00ff00)?>>8;
sir[2]?=?(p?&0x0000ff);
rbs?=?r1?-?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]?=?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?=?MAX(0,?yp)?+?x;
sir?=?stack[i?+?radius];
sir[0]?=?r[yi];
sir[1]?=?g[yi];
sir[2]?=?b[yi];
rbs?=?r1?-?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++)?{
//?Preserve?alpha?channel:?(?0xff000000?&?pix[yi]?)
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]?=?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;
}
}
free(r);
free(g);
free(b);
free(vmin);
free(dv);
free(stack);
return(pix);
}
最后來一張屌絲做demo專業(yè)效果圖:
技術交流QQ群:364595326