31

During this weeks Android Design in Action episode, Adam Koch talked about an app called Etsy, which featured this very cool blur effect applying to the main layout when the Navigation Drawer is pulled out.

Does anyone know how the devs behind Etsy might have implemented this?

Watch it here: http://youtu.be/GjUxEddmjFw?t=22m48s

enter image description here enter image description here

Jakob Harteg
  • 9,587
  • 15
  • 56
  • 78

2 Answers2

67

There's a few parts to this:

1. Creating the blurred bitmap:

We create a downscaled bitmap from the content view behind the drawer when the drawer is first opened (the downscaling makes the blur fast). Then we apply the blur to the downscaled image using RenderScript where available (even faster). For this you should read the blog already mentioned http://nicolaspomepuy.fr/?p=18 and checkout the GlassActionBar project for reference code https://github.com/ManuelPeinado/GlassActionBar.

Note: RenderScript is now available in the support library... but it can't be built using Gradle (for now). Also there are issues with ScriptIntrinsicBlur on some devices notably the Nexus 10 - see Roman Nurik's explanation

2. Showing & Animating the Blur:

Our nav drawer layout contains a hidden ImageView that sits on top of the content.

<FrameLayout
    android:id="@+id/nav_content_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

<!-- our blur image -->
<ImageView
    android:id="@+id/blur_image"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scaleType="centerCrop"
    android:visibility="gone" />

In the Activities onCreate() you'll want to grab a reference to this ImageView and setup a custom drawer listener:

mBlurImage = (ImageView) findViewById(R.id.blur_image);
mDrawerLayout = (DrawerLayout) findViewById(R.id.nav_drawer_layout);

mDrawerToggle = new EtsyNavActionBarDrawerToggle(
            this, 
            mDrawerLayout,
            R.drawable.ic_drawer, 
            R.string.nav_drawer_open, 
            R.string.nav_drawer_closed);

mDrawerLayout.setDrawerListener(mDrawerToggle);

Our drawer has custom scrim color (that's the overlay color) instead of the default transparent black. This also hides the fact that the blurred image is on a downscaled image.

mDrawerLayout.setScrimColor(getResources().getColor(R.color.background_main_v2_glass));

The drawer listener which sets, clears and animates the blurred image:

private class EtsyNavActionBarDrawerToggle extends ActionBarDrawerToggle {

    public EtsyNavActionBarDrawerToggle(Activity activity, DrawerLayout drawerLayout, 
            int drawerImageRes, int openDrawerContentDescRes, int closeDrawerContentDescRes) {
        super(activity, drawerLayout, drawerImageRes, openDrawerContentDescRes, closeDrawerContentDescRes);
    }

    @Override
    public void onDrawerSlide(final View drawerView, final float slideOffset) {
        super.onDrawerSlide(drawerView, slideOffset);
        if (slideOffset > 0.0f) {
            setBlurAlpha(slideOffset);
        }
        else {
            clearBlurImage();
        }
    }

    @Override
    public void onDrawerClosed(View view) {
        clearBlurImage();
    }

}

private void setBlurAlpha(float slideOffset) {
    if (mBlurImage.getVisibility() != View.VISIBLE) {
        setBlurImage();
    }
    ViewHelper.setAlpha(mBlurImage, slideOffset);
}

public void setBlurImage() {
    mBlurImage.setImageBitmap(null);
    mBlurImage.setVisibility(View.VISIBLE);
    Bitmap downScaled = ... // do the downscaling
    Bitmap blurred = ... // apply the blur
    mBlurImage.setImageBitmap(blurred);
}

public void clearBlurImage() {
    mBlurImage.setVisibility(View.GONE);
    mBlurImage.setImageBitmap(null);
}

Lastly the ViewHelper is from NineOldAndroids so we can setAlpha() pre-honeycomb.

denizmveli
  • 2,558
  • 1
  • 23
  • 18
  • 1
    Thanks for such a detailed explanation! Haven't had time to look into yet, but it definitely seems doable, so thank you again. Am I mistaking when thinking you might be one of the devs behind Etsy? – Jakob Harteg Dec 07 '13 at 12:17
  • Thanks for your question! And yes I'm on the Android team at Etsy. – denizmveli Dec 07 '13 at 16:02
  • Jacob, there's one thing that I'm still missing. I was able to do all this myself, but how do you stop the blurred ImageView from getting resized when the keyboard is open? :( – Saket Mar 02 '14 at 13:25
  • ֲֲֲ@denizmveli: great explanation. also the app look and feel super smooth... just to make sure I'm not missing something - bitmap from the content view = getting the drawing cache of the view? – Tal Kanel Mar 08 '14 at 19:05
  • How do you create a downscaled bitmap from the List/Grid I know it that there isn't some standard way like getting bitmap from a View, and some hacky methods have to be used? – djandreski Mar 15 '14 at 22:25
  • @denizmveli I don't know if it's a new feature, but the blurred overlay in the Etsy app updates in real-time! For instance, I can see the updates happening, progress circle spinning. How do you do that so fast? – Saket May 25 '14 at 05:38
  • I'm curious how Etsy does it now too...@denizmveli? – kenyee Jul 09 '14 at 02:12
  • Hey guys - not sure which screen you're talking about with realtime blur? Send me a msg and I can help out. – denizmveli Aug 23 '14 at 00:23
4

Have a look at this blog http://nicolaspomepuy.fr/?p=18

Basically you generate a blur image from original one. I guess in this case original one is generated using getDrawingCache() method, make sure to call setDrawingCacheEnabled() first.

M-Wajeeh
  • 17,204
  • 10
  • 66
  • 103