Размытие в стиле iOS для Android

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

Решено размывать в реальном времени с использованием RenderScript.

Компонент BlurredLayout, наследник FrameLayout

Много кода позаимствовано из ответов на StackOverflow: переопределение dispatchDraw, Android Blur Guide 2014


private void blurRect(Rect rect, float radius, Canvas canvas) {
    Bitmap blurred = Bitmap.createBitmap(mBitmap, rect.left, rect.top,
            rect.right - rect.left, rect.bottom - rect.top);

    Allocation input = Allocation.createFromBitmap(mRenderScript, blurred);
    Allocation output = Allocation.createTyped(mRenderScript, input.getType());
    ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(mRenderScript, Element.U8_4(mRenderScript));
    script.setRadius(radius);
    script.setInput(input);
    script.forEach(output); // FIXME: the most expensive command
    output.copyTo(blurred);

    canvas.drawBitmap(blurred, rect.left, rect.top, BITMAP_PAINT);
    blurred.recycle();
}

Строка с комментарием — это такое чудесное место, где происходит отправка картинки на видеокарту и ожидание результата. Ускорять, увы, нечего :'(

Чтобы создать области размытия, нужно непосредственно внутри BlurredLayout разместить любые View, у которых tag="blur region".


<net.aquadc.widgets.BlurredLayout android:id="@+id/blurred"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <View
        android:layout_width="match_parent"
        android:layout_height="64dp"
        android:background="#66000000"
        android:tag="blur region" />

    <View
        android:layout_width="match_parent"
        android:layout_height="64dp"
        android:layout_gravity="bottom"
        android:background="#22000000"
        android:tag="blur region" />
</net.aquadc.widgets.BlurredLayout>

Аппаратное ускорение должно быть отключено, иначе происходит неведомая хрень. У меня на четырёхлетнем телефоне с Android 4.0.3 тормозит совсем чуть-чуть.

Исходный кот


← клик, если это интересно   |   ↓ место для вопросов и идей