![]() |
Figure 1 |
Introduction
In this article, we will learn how to create layout reveal animation in Android. This feature is available by default from Lollipop. For pre-Lollipop Android versions, an awesome library is available and it is very easy to use.
Circular Reveal animations can be found in WhatsApp while clicking attachment option. It’s more interactive to users. We will learn in detail how to use in Lollipop and Pre-Lollipop devices separately.
Circular Reveal Animation
We already know this feature is available from Lollipop devices. To perform the same features in pre-Lollipop devices we will go for a third party library and it’s awesome to use.
Steps
I have divided this Implementation into 4 steps as shown in the following.
Step 1 - Creating New Project with Android Studio
Step 2 - Setting up the library for the project.
Step 3 - Implementation of Circular Reveal for Pre-Lollipop devices.
Step 4 - Implementation of Circular Reveal for Lollipop devices.
Step 1: Creating New Project with Android Studio
- Open Android Studio and Select create a new project.
- Name the project as per your wish and select an Empty activity.
Figure 5 - Click “finish” button to create a new project in Android Studio.
Step 2 - Setting up the library for the project
- Open App Level gradle file and add the following lines to add the Libraries.
dependencies { ... implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support:support-annotations:27.1.1' implementation 'com.android.support.constraint:constraint-layout:1.1.2' implementation 'com.android.support:design:26.1.0' // Third Party Library implementation 'com.github.ozodrukh:CircularReveal:1.1.0' ... } repositories { maven { url "https://jitpack.io" } }
- Then click “Sync Now” to add the library.
Step 3 - Implementation of Circular Reveal for Pre-Lollipop devices
- Open your designer file that is your XML layout file (In my case, I have opened my xml file) and paste the following code below toolbar if you want.
<io.codetail.widget.RevealFrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/reveal_items" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" android:orientation="horizontal" android:gravity="center" android:padding="16dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <ImageView android:layout_gravity="center" android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_search_green" /> <EditText android:id="@+id/search_box" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Search Here..." android:inputType="text" android:imeOptions="actionSearch" android:maxLines="1"/> </LinearLayout> </LinearLayout> </io.codetail.widget.RevealFrameLayout>
- Here, Reveal Frame Layout itself is used to handle Reveal animation. The Reveal effect can be applied to the whole screen.
- We have initialized the immediate child of the RevealFrameLayout and by default its state should be GONE or INVISIBLE. While changing its View states, the RevealFrameLayout will clips its child’s shape
revealLayout = findViewById(R.id.reveal_items); revealLayout.setVisibility(View.INVISIBLE);
- To perform the animation, import SupportAnimator class from the third party library included for Pre-Lollipop devices.
import io.codetail.animation.SupportAnimator; import io.codetail.animation.ViewAnimationUtils;
- Then add the following to perform the animation in forth and reverse. We need X, Y co-ordinates to perform the animation.
SupportAnimator animator = ViewAnimationUtils.createCircularReveal(layout, cx, cy, 0, radius); animator.setInterpolator(new AccelerateDecelerateInterpolator()); animator.setDuration(800); SupportAnimator animator_reverse = animator.reverse(); if (hidden) { layout.setVisibility(View.VISIBLE); animator.start(); invalidateOptionsMenu(); hidden = false; } else { animator_reverse.addListener(new SupportAnimator.AnimatorListener() { @Override public void onAnimationStart() { } @Override public void onAnimationEnd() { layout.setVisibility(View.INVISIBLE); invalidateOptionsMenu(); hidden = true; } @Override public void onAnimationCancel() { } @Override public void onAnimationRepeat() { } }); animator_reverse.start(); }
- Here,
cx - co-ordinate in X axis.
cy – co-ordinate in Y axis.
These two are required for starting the animation in X, Y axis of the screen. It can be calculated by the following code.
radius - can be calculated by the following code.int cx = revealLayout.getRight(); int cy = revealLayout.getTop();
Animation can be started by SupportAnimator and it is assigned to another SupportAnimator which is used to start the reverse animation. So, the reverse animation will be handled by itself.int radius = Math.max(layout.getWidth(), layout.getHeight());
hidden – is a Boolean value used to know the View State.SupportAnimator animator = ViewAnimationUtils.createCircularReveal(layout, cx, cy, 0, radius); animator.setInterpolator(new AccelerateDecelerateInterpolator()); animator.setDuration(800); SupportAnimator animator_reverse = animator.reverse(); if (hidden) { layout.setVisibility(View.VISIBLE); animator.start(); invalidateOptionsMenu(); hidden = false; } else { animator_reverse.addListener(new SupportAnimator.AnimatorListener() { @Override public void onAnimationStart() { } @Override public void onAnimationEnd() { layout.setVisibility(View.INVISIBLE); invalidateOptionsMenu(); hidden = true; } @Override public void onAnimationCancel() { } @Override public void onAnimationRepeat() { } }); animator_reverse.start(); }
- Probably this does not seem to work from Lollipop devices. So we have to go for a different method which is shown in the next step.
Step 4 - Implementation of Circular Reveal for Lollipop devices
- No 5 in the previous step is slightly changed for Lollipop devices. Instead of “io.codetail.animation.ViewAnimationUtils”, use “android.view.ViewAnimationUtils”.
-
No need to assign animation.reverse(). Instead of it, use the following.
if (hidden) { Animator anim = android.view.ViewAnimationUtils.createCircularReveal(layout, cx, cy, 0, radius); layout.setVisibility(View.VISIBLE); anim.start(); invalidateOptionsMenu(); hidden = false; } else { Animator anim = android.view.ViewAnimationUtils.createCircularReveal(layout, cx, cy, radius, 0); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); layout.setVisibility(View.INVISIBLE); hidden = true; invalidateOptionsMenu(); } }); anim.start(); }
- To reverse the animation, the radius value is interchanged. The animation is handled from toolbar menu options.
Full Code
You can find the full code implementation here.public class MainActivity extends AppCompatActivity {
Toolbar toolbar;
LinearLayout revealLayout;
EditText searchBox;
boolean hidden = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
revealLayout = findViewById(R.id.reveal_items);
revealLayout.setVisibility(View.INVISIBLE);
searchBox = findViewById(R.id.search_box);
searchBox.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
handleKeyboard(searchBox);
searchBox.clearFocus();
Toast.makeText(MainActivity.this, textView.getText().toString(), Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
});
}
void handleKeyboard(View view) {
InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
assert inputManager != null;
inputManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_reveal, menu);
if (hidden) {
menu.findItem(R.id.action_search).setIcon(R.drawable.ic_search);
} else {
menu.findItem(R.id.action_search).setIcon(R.drawable.ic_close);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_search:
int cx = revealLayout.getRight();
int cy = revealLayout.getTop();
makeEffect(revealLayout, cx, cy);
searchBox.setText(null);
return true;
case android.R.id.home:
supportFinishAfterTransition();
return true;
}
return super.onOptionsItemSelected(item);
}
private void makeEffect(final LinearLayout layout, int cx, int cy) {
int radius = Math.max(layout.getWidth(), layout.getHeight());
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
SupportAnimator animator = ViewAnimationUtils.createCircularReveal(layout, cx, cy, 0, radius);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(800);
SupportAnimator animator_reverse = animator.reverse();
if (hidden) {
layout.setVisibility(View.VISIBLE);
animator.start();
invalidateOptionsMenu();
hidden = false;
} else {
animator_reverse.addListener(new SupportAnimator.AnimatorListener() {
@Override
public void onAnimationStart() {
}
@Override
public void onAnimationEnd() {
layout.setVisibility(View.INVISIBLE);
invalidateOptionsMenu();
hidden = true;
}
@Override
public void onAnimationCancel() {
}
@Override
public void onAnimationRepeat() {
}
});
animator_reverse.start();
}
} else {
if (hidden) {
Animator anim = android.view.ViewAnimationUtils.createCircularReveal(layout, cx, cy, 0, radius);
layout.setVisibility(View.VISIBLE);
anim.start();
invalidateOptionsMenu();
hidden = false;
} else {
Animator anim = android.view.ViewAnimationUtils.createCircularReveal(layout, cx, cy, radius, 0);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
layout.setVisibility(View.INVISIBLE);
hidden = true;
invalidateOptionsMenu();
}
});
anim.start();
}
}
}
}
Output Demo
You can find the output of this example.
Follow Us
Were this world an endless plain, and by sailing eastward we could for ever reach new distances