Browse By

Android – Create Circular Reveal Animation for pre-lollipop version

Android – Create Circular Reveal Animation for pre-lollipop version

In the previous article, we have seen Android – Create Circular Reveal Animation And Ripple Effect like Whatsapp. But it is limited to lollipop and above version only. There is no support for older versions.

After publishing that article, we get numbers of request for “Create Circular Reveal Animation for pre-lollipop version”. So, today I am going to learn you how to create Circular reveal animation effect for the pre-lollipop version.

Prerequisites:

Direct Download Full Source Code

 

 

Android – Create Circular Reveal Animation for pre-lollipop version

To make it working in the pre-lollipop version, add following repository & dependency in build.gradle

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

 compile ('com.github.ozodrukh:CircularReveal:1.1.1@aar') 

    {
        transitive = true;
    }

}

Now follow the below steps:

1. Create color.xml in values folder.

<?xml version="1.0" encoding="utf-8"?>
<resources>
        <color name="colorPrimary">#125688</color>
        <color name="colorPrimaryDark">#125688</color>
        <color name="textColorPrimary">#FFFFFF</color>
        <color name="windowBackground">#FFFFFF</color>
        <color name="navigationBarColor">#000000</color>
        <color name="colorAccent">#c8e8ff</color>
</resources>

2. Modify your style.xml file in values folder for effective changes.

<resources>
    <!-- Base application theme. -->
    <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>
    </style>
</resources>

3. 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" />

4. Create activity_main.xml in resource layout (res/layout).

Menu Item like WhatsApp

Menu Item like WhatsApp

<io.codetail.widget.RevealFrameLayout      xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
<include layout="@layout/activity_toolbar"/>
</io.codetail.widget.RevealFrameLayout>

5. Now we will define our layout in this root layout.

<io.codetail.widget.RevealFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
<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="#e1f5fe"
        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>
</io.codetail.widget.RevealFrameLayout>

Performing the Reveal Effect:

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

menu_main.xml

Tools and Menu

Tools 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 centre of clipping circle, change cy as:
    int cy = (mRevealView .getTop() + mRevealView.getBottom())/2;

8. To perform circular reveal, we will use SupportAnimator class of attached library.

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.

 SupportAnimator mAnimator = ViewAnimationUtils.createCircularReveal(mRevealView, cx,    cy, 0, endradius);

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 the icon. The animation will be toggled when tapping 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  onOptionItemSelected(MenuItem item), perform following operations for R.id.action attachment.

int cx = (mRevealView.getLeft() + mRevealView.getRight());
int cy = mRevealView.getTop();
int endradius = Math.max(mRevealView.getWidth(), mRevealView.getHeight());
SupportAnimator mAnimator =
        ViewAnimationUtils.createCircularReveal(mRevealView, cx, cy, 0, endradius);
mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mAnimator.setDuration(400);
mAnimator.start();

11. To perform reverse animation, library’s SupportAnimator provides a method reverse() to reverse the animation. We can’t make view invisible before starting the animation. So, we will add the listener to it and in onAnimationEnd() method. We will hide our view.

 mAnimator = mAnimator.reverse();

12. So, full code of MainActivity.java will be a follows:
The boolean variable is used to handle the visibility of linear layout.

package com.vrs.circulareveal;

import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.ImageButton;
import android.widget.LinearLayout;

import io.codetail.animation.SupportAnimator;
import io.codetail.animation.ViewAnimationUtils;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    boolean hidden = true;
    LinearLayout mRevealView;
    private Toolbar toolbar;
    ImageButton ib_gallery, ib_contacts, ib_location;
    ImageButton ib_video, ib_audio, ib_camera;
    SupportAnimator mAnimator;
    boolean mPressed = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);


        mRevealView = (LinearLayout) findViewById(R.id.reveal_items);
        mRevealView.setVisibility(View.INVISIBLE);
        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);


    }

    @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);
                mPressed=false;
                break;

            case R.id.camera:
                Snackbar.make(v, "Camera Clicked", Snackbar.LENGTH_SHORT).show();
                mRevealView.setVisibility(View.INVISIBLE);
                hidden = true;
                mPressed=false;

                break;

            case R.id.location:
                Snackbar.make(v, "Location Clicked", Snackbar.LENGTH_SHORT).show();
                mRevealView.setVisibility(View.INVISIBLE);
                hidden = true;
                mPressed=false;

                break;

            case R.id.contacts:
                Snackbar.make(v, "Contacts Clicked", Snackbar.LENGTH_SHORT).show();
                mRevealView.setVisibility(View.INVISIBLE);
                hidden = true;
                mPressed=false;


                break;

            case R.id.video:
                Snackbar.make(v, "Video Clicked", Snackbar.LENGTH_SHORT).show();
                mRevealView.setVisibility(View.INVISIBLE);
                hidden = true;
                mPressed=false;


                break;

            case R.id.gallery:
                Snackbar.make(v, "Gallery Clicked", Snackbar.LENGTH_SHORT).show();
                mRevealView.setVisibility(View.INVISIBLE);
                hidden = true;
                mPressed=false;

                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) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        if (id == R.id.action_attachment) {

            if (!mPressed) {
                mPressed = true;


                int cx = (mRevealView.getLeft() + mRevealView.getRight());
                int cy = mRevealView.getTop();
                int endradius = Math.max(mRevealView.getWidth(), mRevealView.getHeight());
                mAnimator =
                        ViewAnimationUtils.createCircularReveal(mRevealView, cx, cy, 0, endradius);
                mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
                mAnimator.setDuration(400);


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

                }
            }
            else {
                    if (mAnimator != null && !mAnimator.isRunning()) {
                        mAnimator = mAnimator.reverse();
                        mAnimator.addListener(new SupportAnimator.AnimatorListener() {
                            @Override
                            public void onAnimationStart() {

                            }

                            @Override
                            public void onAnimationEnd() {
                                mRevealView.setVisibility(View.INVISIBLE);
                                hidden = true;
                                mPressed = false;

                            }

                            @Override
                            public void onAnimationCancel() {

                            }

                            @Override
                            public void onAnimationRepeat() {

                            }

                        });
                        mAnimator.start();
                    }


                }





            return true;

        }


        return super.onOptionsItemSelected(item);


    }
}

13. Now execute application

Android - Create Circular Reveal Animation for pre-lollipop devices

Circular Reveal Animation in pre-lollipop devices

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

Subscribe for more articles!!

Download Full Source Code

 

 

  • Pingback: Android - Create Circular Reveal Animation And Ripple Effect like Whatsapp - Pulse7()

  • Pingback: Android & iOS Application Development | Just another My blog Sites site()

  • Dhanraj Naik

    on double click the menu ,app crashes with the following log :

    java.lang.NullPointerException

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at com.dssp.dhanrajnaik522.watsapplikecircularrevealripple.MainActivityPreLoli.onOptionsItemSelected(MainActivityPreLoli.java:110)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.app.Activity.onMenuItemSelected(Activity.java:2566)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:361)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.support.v7.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:147)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.support.v7.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:100)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.support.v7.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:100)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.support.v7.app.ToolbarActionBar$2.onMenuItemClick(ToolbarActionBar.java:68)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.support.v7.widget.Toolbar$1.onMenuItemClick(Toolbar.java:172)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.support.v7.widget.ActionMenuView$MenuBuilderCallback.onMenuItemSelected(ActionMenuView.java:760)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:811)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:152)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:958)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:948)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.support.v7.widget.ActionMenuView.invokeItem(ActionMenuView.java:618)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.support.v7.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:139)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.view.View.performClick(View.java:4211)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.view.View$PerformClick.run(View.java:17446)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:725)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:92)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.os.Looper.loop(Looper.java:153)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5297)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at java.lang.reflect.Method.invokeNative(Native Method)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at java.lang.reflect.Method.invoke(Method.java:511)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)

    12-20 20:28:25.918 16570-16570/com.dssp.dhanrajnaik522.watsapplikecircularrevealripple E/AndroidRuntime: at dalvik.system.NativeStart.main(Native Method)

    • Bhavika Solanki

      We have solved the issue of null pointer exception. You can download the updated code