Browse By

Android – Create Circular Reveal Animation And Ripple Effect like Whatsapp

Up till now we have seen articles on Material Design like:

  1.  Add Floating Action Button in Android Application
  2.  How to Use RecyclerView with CardView in Android application 
  3.  How to Create Collapsing Toolbar Layout like Whatsapp in Android Application.

Today we are going to learn another concept How to create Circular Reveal Animation And Ripple Effect like Whatsapp.

When I tap “Attach” button of Whatsapp then it displays the menu with circular animation. This effect is known as Circular Reveal Animation and Ripple Effect.

Android – Create Circular Reveal Animation And Ripple Effect like Whatsapp

Android Lollipop introduced a really great new Animator, the Circular Reveal Animation, and Ripple Effect. Let’s see the feature of these two terminologies.

  • Circular Reveal Animation – Reveal animations provide users visual continuity when you show or hide a group of UI elements. 
  • Ripple Effect – Touch feedback in material design provides an instantaneous visual confirmation at the point of contact when users interact with UI elements. The default touch feedback animations for buttons use the new RippleDrawable class, which transitions between different states with a ripple effect.

Let’s see how to perform circular reveal animation and ripple effect like WhatsApp. This example is only for lollipop version. You can also refer  Android – Create Circular Reveal Animation for pre-lollipop version.

Prerequisites:

  • Android Studio version: 1.4
  • Minimum SDK version: 21

Direct Download Full Source Code

 

 

Android – Create Circular Reveal Animation And Ripple Effect like Whatsapp

Your minimum SDK version must be 21.

1. First, add Support Design Library in build.gradle:

compile 'com.android.support:design:22.2.0'

2. Create color.xml in values folder.

<resources>
<color name="colorPrimary">#0277bd</color>
<color name="colorPrimaryDark">#01579b</color>
<color name="textColorPrimary">#FFFFFF</color>
<color name="windowBackground">#FFFFFF</color>
<color name="navigationBarColor">#000000</color>
<color name="colorAccent">#c8e8ff</color>
<color name="ripplecolor">#01579b</color>
</resources>

3. Modify your style.xml(v21) fie in values folder for effective changes.

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="windowNoTitle">true</item>
    <item name="windowActionBar">false</item>
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="selectableItemBackground">?android:selectableItemBackground</item>
    <item name="android:colorControlHighlight">@color/ripplecolor</item>
</style>

4. Create new layout file activity_toolbar.xml in resources layout (res/layout).

activity_toolbar.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
local:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
local:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

5. Let’s create a layout similar to that of WhatsApp’s Attach option. Create activity_main.xml in resources layout ( res/layout).

Android – Create Circular Reveal Animation And Ripple Effect like Whatsapp

Menu Item like WhatsApp

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <include layout="@layout/activity_toolbar" />

    <LinearLayout
        android:id="@+id/reveal_items"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="?attr/actionBarSize"
        android:background="#b3e5fc"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:gravity="center"
            android:orientation="horizontal">

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

                <ImageButton
                    android:id="@+id/gallery"
                    android:layout_width="50dp"
                    android:layout_height="50dp"
                    android:background="@drawable/image" />

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

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

                <ImageButton
                    android:id="@+id/audio"
                    android:layout_width="50dp"
                    android:layout_height="50dp"
                    android:background="@drawable/audio" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="5dp"
                    android:text="Audio" />
            </LinearLayout>

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

                <ImageButton
                    android:id="@+id/video"
                    android:layout_width="50dp"
                    android:layout_height="50dp"
                    android:background="@drawable/play" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="5dp"
                    android:text="Video" />
            </LinearLayout>

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:gravity="center"
            android:orientation="horizontal">

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

                <ImageButton
                    android:id="@+id/camera"
                    android:layout_width="50dp"
                    android:layout_height="50dp"
                    android:background="@drawable/camera" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="5dp"
                    android:text="Camera" />

            </LinearLayout>

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

                <ImageButton
                    android:id="@+id/location"
                    android:layout_width="50dp"
                    android:layout_height="50dp"
                    android:background="@drawable/location" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="5dp"
                    android:text="Location" />

            </LinearLayout>

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

                <ImageButton
                    android:id="@+id/contacts"
                    android:layout_width="50dp"
                    android:layout_height="50dp"
                    android:background="@drawable/contacts" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="5dp"
                    android:text="Contacts" />

            </LinearLayout>

        </LinearLayout>

        <View
            android:layout_width="match_parent"
            android:layout_height="2dp"
            android:background="@android:color/black" />
    </LinearLayout>

</FrameLayout>

Performing the Reveal Effect:

6. Create “menu_main.xml” in res /menu and add the menu item in it.

menu_main.xml

Android - Create Circular Reveal Animation And Ripple Effect like Whatsapp

Toolbar and Menu

 <item
    android:id="@+id/action_attachment"
    android:icon="@drawable/attachment"
    android:title="Media"
    app:showAsAction="ifRoom" />

7. To perform animation we need following parameters:

The radius of the circular reveal and X, Y coordinates to start the animation from.

  • The radius can be obtained using this method:
int radius = Math.max(mRevealView .getWidth(), mRevealView.getHeight());
  • To achieve Reveal effect from the top right.

    int cx = (mRevealView.getLeft() + mRevealView.getRight());
    int cy = mRevealView.getTop();
  • To find the center of clipping circle, change cy as:

int cy = (mRevealView .getTop() + mRevealView.getBottom())/2;


8. To perform circular reveal, we will use
ViewAnimationUtils.createCircularReveal (View view, int centerX, int centerY, float startRadius, float endRadius). This method enables us to animate a clipping circle to reveal or hide a view.

It takes following parameters:

view The View will be clipped to the animating circle.
centerX The x coordinate of the center of the animating circle, relative to view.
centerY The y coordinate of the center of the animating circle, relative to view.
startRadius The starting radius of the animating circle.
endRadius The ending radius of the animating circle

9. Create MainActivity.java  and inflate activity_main.xml and menu_main.xml in it.

MainActivity.java

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return true;
    }
}

10. In MainActivity.java, we will give circular reveal effect to an icon. The animation will be toggled when we tap the Attach button. The contents of the Linear layout will be displayed, and hidden alternatively.

 When we tap menu icon, start radius will be zero and end radius will be width and height of the layout and layout will be visible to the users. So, in onOptionsItemSelected(MenuItem item), perform following operations on id of action_attachment.

int startradius=0;
int endradius = Math.max(mRevealView.getWidth(), mRevealView.getHeight());

Animator animator = ViewAnimationUtils.createCircularReveal(mRevealView, cx, cy, startradius, endradius);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(400);
animator.start();


11.
To perform reverse animation , change the starting radius to the radius or the extent to which circular reveal animation is to be shown and ending radius to zero. In our case, it is the width and height length of linear layout.

int reverse_startradius = Math.max(mRevealView.getWidth(),mRevealView.getHeight());
int reverse_endradius=0;

Animator animate = ViewAnimationUtils.createCircularReveal(mRevealView,cx,cy,reverse_startradius,reverse_endradius);
animate.start();

12. So, Full code of MainActivity.java will be as follows:
A boolean variable is used to handle the visibility of linear layout.

package com.vrs.circular_ripple_lollipop;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.ImageButton;
import android.widget.LinearLayout;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    Toolbar toolbar;
    boolean hidden=true;
    LinearLayout mRevealView;
    ImageButton ib_gallery,ib_contacts,ib_location;
    ImageButton ib_video,ib_audio,ib_camera;

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        toolbar=(Toolbar)findViewById(R.id.toolbar);
        mRevealView = (LinearLayout) findViewById(R.id.reveal_items);
        ib_audio=(ImageButton)findViewById(R.id.audio);
        ib_camera=(ImageButton)findViewById(R.id.camera);
        ib_contacts=(ImageButton)findViewById(R.id.contacts);
        ib_gallery=(ImageButton)findViewById(R.id.gallery);
        ib_location=(ImageButton)findViewById(R.id.location);
        ib_video=(ImageButton)findViewById(R.id.video);
        ib_audio.setOnClickListener(this);
        ib_camera.setOnClickListener(this);
        ib_contacts.setOnClickListener(this);
        ib_gallery.setOnClickListener(this);
        ib_location.setOnClickListener(this);
        ib_video.setOnClickListener(this);
        setSupportActionBar(toolbar);
        mRevealView.setVisibility(View.INVISIBLE);
    }

   // imagebutton click events
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.audio:
                Snackbar.make(v, "Audio Clicked", Snackbar.LENGTH_SHORT).show();
                mRevealView.setVisibility(View.INVISIBLE);
                hidden=true;
                break;
            case R.id.camera:
                Snackbar.make(v, "Camera Clicked", Snackbar.LENGTH_SHORT).show();
                mRevealView.setVisibility(View.INVISIBLE);
                hidden=true;
                break;
            case R.id.location:
                Snackbar.make(v, "Location Clicked", Snackbar.LENGTH_SHORT).show();
                mRevealView.setVisibility(View.INVISIBLE);
                hidden=true;
                break;
            case R.id.contacts:
                Snackbar.make(v, "Contacts Clicked", Snackbar.LENGTH_SHORT).show();
                mRevealView.setVisibility(View.INVISIBLE);
                hidden=true;
                break;
            case R.id.video:
                Snackbar.make(v, "Video Clicked", Snackbar.LENGTH_SHORT).show();
                mRevealView.setVisibility(View.INVISIBLE);
                hidden=true;
                break;
            case R.id.gallery:
                Snackbar.make(v, "Gallery Clicked", Snackbar.LENGTH_SHORT).show();
                mRevealView.setVisibility(View.INVISIBLE);
                hidden=true;
                break;
        }
    }

   @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {

            return true;
        }   

         else if(id== R.id.action_attachment){// attachment icon click event

            // finding X and Y co-ordinates
            int cx = (mRevealView.getLeft() + mRevealView.getRight());
            int cy = (mRevealView.getTop());

            // to find  radius when icon is tapped for showing layout
            int startradius=0;
            int endradius = Math.max(mRevealView.getWidth(), mRevealView.getHeight());

              // performing circular reveal when icon will be tapped
            Animator animator = ViewAnimationUtils.createCircularReveal(mRevealView, 					cx, cy, startradius, endradius);
            animator.setInterpolator(new AccelerateDecelerateInterpolator());
            animator.setDuration(400);

            //reverse animation
            // to find radius when icon is tapped again for hiding layout
            //  starting radius will be the radius or the extent to which circular reveal animation is to be shown

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

            //endradius will be zero
            int reverse_endradius=0;

           // performing circular reveal for reverse animation
            Animator animate = ViewAnimationUtils.createCircularReveal(mRevealView,cx,cy,reverse_startradius,reverse_endradius);
            if(hidden){

		 	// to show the layout when icon is tapped
                	mRevealView.setVisibility(View.VISIBLE);
	           animator.start();
      		hidden = false;
            }
            else {
                mRevealView.setVisibility(View.VISIBLE);

                  // to hide layout on animation end
                animate.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        super.onAnimationEnd(animation);
                        mRevealView.setVisibility(View.INVISIBLE);
                        hidden = true;
                    }
                });
                animate.start();
            }
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

13. Now execute application

Android -Create Circular Reveal Animation And Ripple Effect like Whatsapp

Circular Reveal Animation And Ripple Effect like Whatsapp

 

I hope you like this article. Share your views to to improve content. Happy Coding !!!

Subscribe for more articles!!

Download Full Source Code