前言
????Android開發(fā)過程中,總是需要與IOS坐比較,每次產(chǎn)品經(jīng)理都要問,為什么IOS能做到,Android做不到。并不是Android做不到,主要原因是IOS下,有些控件是有現(xiàn)成的組件庫的,Android沒有,所以Android需要去自己繪制。
????上次產(chǎn)品經(jīng)理就讓我寫一個功能,需要在頁面滑動時,頂部導航欄需要從透明到模糊漸變,一定程度后不再改變。查閱了網(wǎng)上各種資料,發(fā)現(xiàn)關于Android高斯模糊的確有很多文章,但他們都是對于一個靜態(tài)的頁面或者圖片做模糊,使用RenderScript高效計算平臺進行模糊就好了。但我需要的效果中,頁面是動態(tài)的,底下View是一直在改變的,怎么讓他在需要的區(qū)域模糊呢。
????廢話不多說,先看實現(xiàn)效果,點擊看視頻效果,更加清晰流暢。
????上面的效果是大家想要的嗎?
實現(xiàn)方式
其實我的思路很簡單,就只有四步,獲取位置-裁剪-轉化-模糊
Step 1 通過onLayout方法,先獲取目標區(qū)域的位置
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// Log.i("BlurView", "onLayoutBlurView changed=" + changed + " left=" + left + " ,top=" + top + " ,right=" + right + " ,bottom=" + bottom);
lastActionTime = System.currentTimeMillis();
//獲取Bitmap從View
setBlurBitmapFromView(getLeft(), getTop(), getRight(), getBottom());
}
Step 2 在整個Windows窗口中,對目標區(qū)域的View進行裁剪
/**
* 獲取需要Bitmap
* @param left
* @param top
* @param right
* @param bottom
*/
private void setBlurBitmapFromView(int left, int top, int right, int bottom) {
//獲取父View
ViewGroup parent = (ViewGroup) getParent();
//將此布局從父View移除,在截圖不截進此視圖。
parent.removeView(this);
//獲取對應位置的Bitmap對象
bitmap = getDownscaledBitmapForView(parent, new Rect(left, top, right, bottom), downScaleFactor);
//截完圖獲取到bitmap之后,再把此View加載到父布局上
parent.addView(this);
printfActionTime("圖片處理");
//模糊處理
bitmap = blurBitmap(bitmap, mBlurRadius);
printfActionTime("模糊處理");
}
Step 3 然后把裁剪下來的View轉化成Bitmap,此時先做一次Bitmap壓縮,為了讓RenderScript計算的更快
/**
* 裁剪View,View轉Bitmap,同時進行Bitmap壓縮
* @param view
* @param crop
* @param downscaleFactor 壓縮比例
* @return
*/
private Bitmap getDownscaledBitmapForView(View view, Rect crop, float downscaleFactor) {
int width = Math.round(crop.width() * downscaleFactor);
int height = Math.round(crop.height() * downscaleFactor);
if (view.getWidth() <= 0 || view.getHeight() <= 0 || width <= 0 || height <= 0) {
throw new IllegalArgumentException("No screen available (width or height = 0)");
}
float dx = -crop.left * downscaleFactor;
float dy = -crop.top * downscaleFactor;
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Matrix matrix = new Matrix();
matrix.preScale(downscaleFactor, downscaleFactor);
matrix.postTranslate(dx, dy);
canvas.setMatrix(matrix);
view.draw(canvas);
return bitmap;
}
Step 4 最后再進行模糊處理就好了
/**
* 模糊處理
* @param image
* @param blurRadius
* @return
*/
public Bitmap blurBitmap(Bitmap image, float blurRadius) {
// 創(chuàng)建一張渲染后的輸出圖片
Bitmap outputBitmap = Bitmap.createBitmap(image);
// Log.i("BlurView", "onLayoutBlurView bitmap.size=" + inputBitmap.getByteCount());
// 由于RenderScript并沒有使用VM來分配內(nèi)存,所以需要使用Allocation類來創(chuàng)建和分配內(nèi)存空間
// 創(chuàng)建Allocation對象的時候其實內(nèi)存是空的,需要使用copyTo()將數(shù)據(jù)填充進去
Allocation tmpIn = Allocation.createFromBitmap(rs, image);
Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
// 設置渲染的模糊程度, 25f是最大模糊度
blurScript.setRadius(blurRadius);
// 設置blurScript對象的輸入內(nèi)存
blurScript.setInput(tmpIn);
// 將輸出數(shù)據(jù)保存到輸出內(nèi)存中
blurScript.forEach(tmpOut);
// 將數(shù)據(jù)填充到Allocation中
tmpOut.copyTo(outputBitmap);
image.recycle();
rs.destroy();
return outputBitmap;
}
????思路其實很簡單的,代碼也非常簡潔,需要在復雜一點的,可以自己去擴展。
自取
源碼地址:BlurView
Github地址:Open-View
有幫助就幫忙點個贊吧~