Подтвердить что ты не робот

Прозрачный размытый вид, который размывает макет под

У меня есть Linringayout, который я сделал прозрачным, и теперь я ищу способ дать эффект Blur, так что когда-либо под ним размывается. Как и Windows 7 Aero (см. Снимок экрана).

Я знаю, что вы можете сделать эффект размытия следующим образом:

getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);

Но это относится только к тому, как размывание фона при появлении диалогового окна.

Я уже почти час гуляю, и ничего не могу найти. У кого-нибудь есть предложения по тому, как это сделать?

Спасибо

Windows 7 Aero effect

4b9b3361

Ответ 1

Это было на мой взгляд в течение некоторого времени, и я только что реализовал его благодаря вашему вопросу.

Чтобы это сделать, нам нужно нарисовать макет, который находится ниже нашего размытия, в растровое изображение. Затем, используя алгоритм размытия, мы должны размыть это растровое изображение и, наконец, нарисовать размытое растровое изображение в качестве нашего макета размытия.

К счастью, андроид имеет механизм кэширования чертежа, поэтому первая часть проста. Мы можем просто включить кешированный чертеж для нашего макета и использовать getDrawingCache() для получения растрового изображения из него.

Теперь нам нужен быстрый алгоритм размытия. Я использовал этот fooobar.com/questions/37704/...

Вот он.

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.View;

import java.lang.ref.WeakReference;
import java.util.InputMismatchException;

/**
 * A drawable that draws the target view as blurred using fast blur
 * <p/>
 * <p/>
 * TODO:we might use setBounds() to draw only part a of the target view
 * <p/>
 * Created by 10uR on 24.5.2014.
 */
public class BlurDrawable extends Drawable {

    private WeakReference<View> targetRef;
    private Bitmap blurred;
    private Paint paint;
    private int radius;


    public BlurDrawable(View target) {
        this(target, 10);
    }

    public BlurDrawable(View target, int radius) {
        this.targetRef = new WeakReference<View>(target);
        setRadius(radius);
        target.setDrawingCacheEnabled(true);
        target.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_AUTO);
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setFilterBitmap(true);
    }

    @Override
    public void draw(Canvas canvas) {
        if (blurred == null) {
            View target = targetRef.get();
            if (target != null) {
                Bitmap bitmap = target.getDrawingCache(true);
                if (bitmap == null) return;
                blurred = fastBlur(bitmap, radius);
            }
        }
        if (blurred != null && !blurred.isRecycled())
            canvas.drawBitmap(blurred, 0, 0, paint);
    }

    /**
     * Set the bluring radius that will be applied to target view bitmap
     *
     * @param radius should be 0-100
     */
    public void setRadius(int radius) {
        if (radius < 0 || radius > 100)
            throw new InputMismatchException("Radius must be 0 <= radius <= 100 !");
        this.radius = radius;
        if (blurred != null) {
            blurred.recycle();
            blurred = null;
        }
        invalidateSelf();
    }


    public int getRadius() {
        return radius;
    }

    @Override
    public void setAlpha(int alpha) {
    }


    @Override
    public void setColorFilter(ColorFilter cf) {

    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }

    /**
     * from /questions/37704/fast-bitmap-blur-for-android-sdk/274214#274214
     * <p/>
     * <p/>
     * <p/>
     * Stack Blur v1.0 from
     * http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
     * <p/>
     * Java Author: Mario Klingemann <mario at quasimondo.com>
     * http://incubator.quasimondo.com
     * created Feburary 29, 2004
     * Android port : Yahel Bouaziz <yahel at kayenko.com>
     * http://www.kayenko.com
     * ported april 5th, 2012
     * <p/>
     * This is a compromise between Gaussian Blur and Box blur
     * It creates much better looking blurs than Box Blur, but is
     * 7x faster than my Gaussian Blur implementation.
     * <p/>
     * I called it Stack Blur because this describes best how this
     * filter works internally: it creates a kind of moving stack
     * of colors whilst scanning through the image. Thereby it
     * just has to add one new block of color to the right side
     * of the stack and remove the leftmost color. The remaining
     * colors on the topmost layer of the stack are either added on
     * or reduced by one, depending on if they are on the right or
     * on the left side of the stack.
     * <p/>
     * If you are using this algorithm in your code please add
     * the following line:
     * <p/>
     * Stack Blur Algorithm by Mario Klingemann <[email protected]>
     */
    private static Bitmap fastBlur(Bitmap sentBitmap, int radius) {


        Bitmap 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];
        Log.e("pix", w + " " + h + " " + pix.length);
        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++) {
                // 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);
    }

}

Использование:

View beneathView = //the view that beneath blur view
View blurView= //blur View

BlurDrawable blurDrawable = new BlurDrawable(beneathView, radius);

blurView.setBackgroundDrawable(blurDrawable);

И как мое тестовое приложение выглядело следующим образом:

test application

Я решил не использовать это, потому что он слишком хакерский и не выглядит таким крутым, как я думал, что это будет на первом месте.

Ответ 2

Размытие в реальном времени на андроиде по-прежнему является препятствием. Здесь всестороннее сравнение некоторых из жизнеспособных механизмов:

StackBlur (уже указан в ответе Onur под именем fastBlur):

Как выглядит (в радиусе 20):

enter image description here

Записанное время (мс) для генерации каждого BitmapDrawable:

I/(10266): Total time taken: 35
I/(10266): Total time taken: 54
I/(10266): Total time taken: 48
I/(10266): Total time taken: 36
I/(10266): Total time taken: 48
I/(10266): Total time taken: 39
I/(10266): Total time taken: 49
I/(10266): Total time taken: 50
I/(10266): Total time taken: 35
I/(10266): Total time taken: 47

Среднее value = > ~ 44,1 мс = > 22 обратных в секунду

Renderscript

ScriptIntrinsicBlur обеспечивает последовательное быстрое размытие. Его доступный api 8 с помощью библиотеки поддержки.

Как выглядит (в радиусе 20):

enter image description here

Записанное время (мс) для генерации каждого BitmapDrawable:

I/(9342): Total time taken: 14
I/(9342): Total time taken: 16
I/(9342): Total time taken: 13
I/(9342): Total time taken: 28
I/(9342): Total time taken: 14
I/(9342): Total time taken: 12
I/(9342): Total time taken: 14
I/(9342): Total time taken: 19
I/(9342): Total time taken: 13
I/(9342): Total time taken: 13

Среднее value = > ~ 15,6 мс = > 64 обратных в секунду

RenderScript (радиус = 3) + масштабирование (20%):

Это еще один способ получить приличное (?), но быстрое размытие. Мы делаем масштабирование растрового изображения до части его размера - скажем, 20% - и применяем алгоритм размытия в уменьшенной версии. Как только это будет сделано, мы масштабируем растровое изображение до его первоначального размера. Результаты не так хороши, как использование алгоритма размытия на оригинале, но они проходимы. Также обратите внимание, что значение радиуса не должно быть слишком высоким, или результирующая растровая карта будет неразличимой.

Как выглядит:

enter image description here

Записанное время (мс) для генерации каждого BitmapDrawable:

I/(11631): Total time taken: 5
I/(11631): Total time taken: 19
I/(11631): Total time taken: 3
I/(11631): Total time taken: 7
I/(11631): Total time taken: 7
I/(11631): Total time taken: 5
I/(11631): Total time taken: 7
I/(11631): Total time taken: 17
I/(11631): Total time taken: 5
I/(11631): Total time taken: 4

Среднее value = > ~ 7.9 мс = > 126 ссылок в секунду

StackBlur (радиус = 3) + Масштабирование (20%):

Та же концепция, что и # 3 выше. Уменьшите размер до 20% и примените stackblur на масштабированном растровом изображении.

enter image description here

I/(12690): Total time taken: 4
I/(12690): Total time taken: 20
I/(12690): Total time taken: 4
I/(12690): Total time taken: 4
I/(12690): Total time taken: 5
I/(12690): Total time taken: 5
I/(12690): Total time taken: 4
I/(12690): Total time taken: 21
I/(12690): Total time taken: 3
I/(12690): Total time taken: 4

Среднее value = > ~ 7.4 мс = > 135 ссылок в секунду

Тесты, выполненные на Nex4. Размер растрового изображения - 200px x 200px

Другой совет: методы buildDrawingCache() и getDrawingCache() сами занимают много времени. Альтернативой этому является создание растрового изображения с использованием размеров вида, которое необходимо размыть:

Bitmap toDrawOn = Bitmap.createBitmap(viewWidth, viewHeight, Bitmap.Config.ARGB_8888);

// Create a canvas - assign `toDrawOn` as an offscreen bitmap to it
Canvas holdingCanvas = new Canvas(toDrawOn);

// Now, let the view draw itself on this canvas
yourView.draw(holdingCanvas);

Теперь вид представлен на toDrawOn, и вы можете использовать его, как вам угодно.

Это, по моему опыту, намного быстрее, чем генерация и доступ к кешу чертежа.

Если вам нужна помощь в реализации любого из перечисленных выше четырех методов, дайте мне знать в комментариях.

Имейте в виду, что приведенные выше gifs были уменьшены и еще много чего. Если вы хотите просмотреть исходные файлы с экрана (mp4) - проверьте ссылку.

Ответ 3

Здесь - хороший способ "Размыть изображения, эффективно используя Renderscript" по GDE Марио Вивиани.

Вот копия/вставка:

Размытие изображений - это эффект, который необходимо достичь многим разработчикам, и для его выполнения может потребоваться некоторое время и усилия. Кроме того, поскольку требуется много манипуляций с изображениями, если оно не соответствующим образом закодировано, это может быть очень больно с точки зрения использования ЦП и памяти.

Там быстрое и эффективное решение для размытия изображений, которое Renderscript.

Доступно с API 11 (Honeycomb), Renderscript позволяет использовать ускорение GPU и нацелено на высокопроизводительные 3D-рендеринг и вычисления. Renderscript представляет собой действительно сложный и сочлененный продукт и позволяет осуществлять глубокую настройку и кодирование с использованием родного языка C99, что позволяет переносить, производительность и удобство использования.

Однако, поскольку API 17 (4.2.2) Renderscript предлагает некоторые встроенные функции, которые выполняют четко определенные операции, называемые Intrinsics, Intrinsics - это предварительно написанные сценарии, позволяющие выполнять такие операции, как Blur, Blen, Matrix Convolution и т.д., Без необходимости писать код Renderscript.

Вот простой способ, который я написал, чтобы легко закончить эффективно применять фильтр Blur к растровому изображению:

public Bitmap blurBitmap(Bitmap bitmap) {

    //Let create an empty bitmap with the same size of the bitmap we want to blur
    Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);

    //Instantiate a new Renderscript
    RenderScript rs = RenderScript.create(getApplicationContext());

    //Create an Intrinsic Blur Script using the Renderscript
    ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));

    //Create the in/out Allocations with the Renderscript and the in/out bitmaps
    Allocation allIn = Allocation.createFromBitmap(rs, bitmap);
    Allocation allOut = Allocation.createFromBitmap(rs, outBitmap);

    //Set the radius of the blur
    blurScript.setRadius(25.f);

    //Perform the Renderscript
    blurScript.setInput(allIn);
    blurScript.forEach(allOut);

    //Copy the final bitmap created by the out Allocation to the outBitmap
    allOut.copyTo(outBitmap);

    //recycle the original bitmap
    bitmap.recycle();

    //After finishing everything, we destroy the Renderscript.
    rs.destroy();

    return outBitmap;
}

RenderScript Blurred Image

и... вуаля! Размытое растровое изображение!: -)

Помните, что для запуска предыдущего кода вам потребуется минимум API 17 (4.2.2).

Вот суть этого метода: https://gist.github.com/Mariuxtheone/903c35b4927c0df18cf8

Если вы хотите узнать больше об Intrinsics, ознакомьтесь с этим сообщением в блоге разработчиков Android: http://android-developers.blogspot.it/2013/08/renderscript-intrinsics.html

Если вам интересно узнать больше о Renderscript, ознакомьтесь с этими ссылками: http://android-developers.blogspot.it/2011/02/introducing-renderscript.html http://android-developers.blogspot.it/2011/03/renderscript.html

Ответ 4

Это невозможно сделать легко, используя функции макета.

Я бы предложил рисовать родительский вид на холст, как описано здесь: Как сделать любое изображение для рисования на холст?, при этом скрытый вид переднего плана. Затем размыте холст и нарисуйте представление переднего плана, используя эти данные в качестве фона или его части.

Это будет очень ресурсоемкая операция, если вы хотите, чтобы этот эффект был вживую. Вы должны хотя бы попробовать кэшировать результат размытия.

Ответ 5

Попытайтесь использовать эту библиотеку, я думаю, вам просто нужно передать представление на нее, и она будет работать...

https://github.com/kikoso/android-stackblur

Ответ 6

шаг 1. Вырезать часть фонового изображения в растровом изображении, которое должно быть размыто.

Шаг 2. Размытие этой части растрового изображения.

Шаг 3. Установите растровое изображение в качестве фона.

метод java

private void applyBlur(final View image, final View layout) {
image.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            image.getViewTreeObserver().removeOnPreDrawListener(this);
            image.buildDrawingCache();

            Bitmap bmp = image.getDrawingCache();

            Bitmap overlay = Bitmap.createBitmap((int) (layout.getMeasuredWidth()),
                    (int) (layout.getMeasuredHeight()), Bitmap.Config.ARGB_8888);

            Canvas canvas = new Canvas(overlay);

            canvas.translate(-layout.getLeft(), -layout.getTop());
            canvas.drawBitmap(bmp, 0, 0, null);

            RenderScript rs = RenderScript.create(getActivity());

            Allocation overlayAlloc = Allocation.createFromBitmap(
                    rs, overlay);

            ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(
                    rs, overlayAlloc.getElement());

            blur.setInput(overlayAlloc);

            blur.setRadius(20);

            blur.forEach(overlayAlloc);

            overlayAlloc.copyTo(overlay);

            layout.setBackground(new BitmapDrawable(
                    getResources(), overlay));

            rs.destroy();
            return true;
        }
    });
}

...

теперь вызывается эта функция:

метод вызова

applyBlur (detail_main_image, titleLayout);

...

//где detail_main_image - это изображение, на котором я должен показать размытие // и titleLayout - это вид, на котором я должен установить размытие фона.