Android自定義View之仿IOS模糊控件 (標題欄滑動過程中實時模糊)

前言

????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

有幫助就幫忙點個贊吧~

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容