Circular Reveal Effect like WhatsApp in Android

While sending a photo through WhatsApp, I noticed the ‘Attach’ button performs a neat Circular Reveal effect. My phone being JellyBean, I was surprised to see a Lollipop only transition. Thanks to a neat library, we can mimic the exact same thing for pre Lollipop too.

The Reveal Effect

Touch feedback in material design provides an instantaneous visual confirmation at the point of contact when users interact with UI elements.

The Reveal Effect uses the RippleDrawable class to achieve this. So visually, you can tell that it is similar to the Ripple effect. The only difference being that a Ripple is a touch feedback denoted by a color spreading from a point of contact, while the Reveal effect does the same animation, but for displaying a view.

icon icon

WhatsApp’s version

Here’s how it looks on WhatsApp, after their Material Design upgrade.

whatsapp-reveal-effect

This is exactly what we’re going to create. Sorry about not having a video/ gif. If you still don’t get what I’m talking about then scroll down to the end of the post.

Setup

The issue is, this animation as said before is intended for Lollipop and above ONLY. There is no support library to help us out here. So no version below Lollipop can perform this.

However, there is a neat library that’s managed to backport this for us. We will be using the same, for our purpose. The good thing about the library is that, the methods are exactly the same, which is convenient. Though one must be careful about the imports.

Circular Reveal Library

We’ll start by including the library in our build.gradle file. Add the repository first, and then the dependency.

repositories {
    maven {
        url "https://jitpack.io"
    }
}

dependencies {
    compile 'com.github.ozodrukh:CircularReveal:1.1.0'
}

Layout

Let’s create a layout similar to that of WhatsApp’s Attach option.

layout-2015-07-17-092633

Here’s the layout skeleton if you’re interested. Honestly this layout could be any layout that you want to reveal using this effect, even entire screen transitions could be done.

<io.codetail.widget.RevealFrameLayout
           android:layout_width="match_parent"
           android:layout_height="wrap_content">

           <LinearLayout
               android:id="@+id/reveal_items"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:orientation="horizontal"  >

               <LinearLayout
                   android:layout_width="0dp"
                   android:layout_height="wrap_content"
                   android:layout_weight="1"
                   android:gravity="center"
                   android:orientation="vertical">

                   <ImageButton
                       android:layout_width="70dp"
                       android:layout_height="70dp"
                       android:background="@drawable/icon_camera" />

                   <TextView
                       android:layout_width="wrap_content"
                       android:layout_height="wrap_content"
                       android:layout_marginTop="16dp"
                       android:text="Gallery" />
               </LinearLayout>

               <!-- Other 2 icons here-->
               
           </LinearLayout>

       </io.codetail.widget.RevealFrameLayout>

Note the RevealFrameLayout widget. This comes from the library we imported. This is nothing but a FrameLayout. To perform the animation, we will reference the immediate child layout of this frame. While that child (here being the LinearLayout) with id reveal_items will animate, it’s shape will be clipped by the outer RevealFrameLayout.

Performing the Reveal Effect

Head over to your Activity.java and lets get that animation working. The animation will be toggled when we tap the Attach (clip) button. The contents of the RevealFrameLayout will be displayed, and hidden alternatively.

Remember I said we need to reference the immediate child of the RevealFrameLayout.

LinearLayout mRevealView = (LinearLayout) findViewById(R.id.reveal_items);
mRevealView.setVisibility(View.INVISIBLE);

The view will be inivisible as by default it remains hidden, only presenting itself when we tap Attach.

Our Attach button will be in our Toolbar, included using a menu resource.

icon icon
... 
<item
        android:id="@+id/action_clip"
        android:icon="@drawable/ic_action_editor_attach_file"
        android:title="Media"
        app:showAsAction="ifRoom" />
...

The meat of the action takes place in the onOptionsItemSelected() method. Here is where the Toolbar (ActionBar) menu item’s click actions are defined.

 public boolean onOptionsItemSelected(MenuItem item) {
  
   switch (item.getItemId()) {
         case R.id.action_clip:
        // handle animation here
             return true;  
     }

     return super.onOptionsItemSelected(item);
}

Animation Prerequisites

To perform the animation, two parameters are needed:

  1. X, Y coordinates to start the animation from
  2. Radius of the circular reveal

WhatsApp performs the Reveal effect from the top right.

int cx = (mRevealView.getLeft() + mRevealView.getRight());
int cy = mRevealView.getTop();

If you need it from the center, then just change cy to this instead:  int cy = (mRevealView.getTop() + mRevealView.getBottom())/2;

The radius can be obtained using this method:

int radius = Math.max(mRevealView.getWidth(), mRevealView.getHeight());

ViewAnimationUtils

Now we can finally initiate the reveal effect.

SupportAnimator animator =
                      ViewAnimationUtils.createCircularReveal(mRevealView, cx, cy, 0, radius);
              animator.setInterpolator(new AccelerateDecelerateInterpolator());
              animator.setDuration(400);

SupportAnimator animator_reverse = animator.reverse();

NOTE: Be very careful of the imports here. ViewAnimationUtils is imported from from the external library, and NOT the default android.view.ViewAnimationUtils import.

animator will be used for revealing the view on tap, while animator_reverse in essense reverses the animation for hiding back the view when tapped again.

Animation Toggle

We will use a simple boolean hidden  to handle the toggling.

if (hidden) {
                  mRevealView.setVisibility(View.VISIBLE);
                  animator.start();
                  hidden = false;

              } else {

                  animator_reverse.addListener(new SupportAnimator.AnimatorListener() {
                  
                      @Override
                      public void onAnimationEnd() {
                          mRevealView.setVisibility(View.INVISIBLE);
                          hidden = true;
                      }
                      ...
                  });

                  animator_reverse.start();
              }

Note that we need to make the view visible before we being the reveal effect. While this simply works, its not the same for the reverse effect. The library’s SupportAnimator provides a method reverse() to reverse the animation. We cannot just set the view invisible before starting the animation. The animation performed will never be visible.

For this we will use the AnimatorListener. Once the reverse animation ends, the convenient onAnimationEnd() method will allow us to hide the view.

Be sure to update the boolean hidden accordingly in the if and else cases.


Lollipop Fix

Strangely, this doesn’t seem to work on Lollipop 5.0.1 and above. As in, the transition itself doesn’t work. A simple workaround for this would be to use Android’s native ViewAnimationUtils for devices Lollipop and above.

Simply wrap the code you just wrote like this.

 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
    // Your previously written code
} else {
  // Same code here but import ViewAnimationUtils from android.view.ViewAnimationUtils
   Animator anim = android.view.ViewAnimationUtils.createCircularReveal(mRevealView, cx, cy, 0, radius);
  ...
}

Hope the comments there were self explanatory. There’s no need for the support animator as well. You can look at my code here, just in case.


 

That’s it. While this post, for the most part was just my explaining, the actual implementation itself is pretty simply and straightforward once you do it yourself. The Circular Reveal library by ozodrukh is brilliant and works nicely.

Here’s the final output and it looks amazing.

reveal-effect-final

As always, here’s the link to my Git for code reference.

49596856
You can get creative with which views your using, be it a simple view or an entire screen transition itself! I simply used WhatsApp’s Attach button as an example.

Show me what you can come up with and drop em in the comments below.

Cheers!

App developer with an eye for design. Loves to create apps with good UI/ UX that doesn’t annoy people. In his spare time, he likes to draw and paint.

Suleiman

App developer with an eye for design. Loves to create apps with good UI/ UX that doesn't annoy people. In his spare time, he likes to draw and paint.

You may also like...