These are the three steps to show the Material Design circular animation when launching an Activity. Make sure to only use this animation when it makes sense - it is meant to make it clear to the user that a button results in the screen being opened.
Can also be used for revealing parts of the UI instead of entire Activities - the required simplification of these snippets is left as an exercise to the reader ;)
Step 1: Make sure the launched activity starts out with a transparent background
Add this to the AndroidManifest.xml
:
<activity android:name=".SecondActivity"
android:theme="@style/AppTheme.Transparent"/>
and add this to the styles:
<style name="AppTheme.Transparent" parent="AppTheme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>
Step 2: Launch the activity
We’ll put this inside FirstActivity.java
:
public void presentActivity(View view) {
ActivityOptionsCompat options = ActivityOptionsCompat.
makeSceneTransitionAnimation(this, view, "transition");
int revealX = (int) (view.getX() + view.getWidth() / 2);
int revealY = (int) (view.getY() + view.getHeight() / 2);
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra(SecondActivity.EXTRA_CIRCULAR_REVEAL_X, revealX);
intent.putExtra(SecondActivity.EXTRA_CIRCULAR_REVEAL_Y, revealY);
ActivityCompat.startActivity(this, intent, options.toBundle());
}
Step 3: Animate
Put this in SecondActivity.java
:
public static final String EXTRA_CIRCULAR_REVEAL_X = "EXTRA_CIRCULAR_REVEAL_X";
public static final String EXTRA_CIRCULAR_REVEAL_Y = "EXTRA_CIRCULAR_REVEAL_Y";
View rootLayout;
private int revealX;
private int revealY;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
final Intent intent = getIntent();
rootLayout = findViewById(R.id.root_layout);
if (savedInstanceState == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
intent.hasExtra(EXTRA_CIRCULAR_REVEAL_X) &&
intent.hasExtra(EXTRA_CIRCULAR_REVEAL_Y)) {
rootLayout.setVisibility(View.INVISIBLE);
revealX = intent.getIntExtra(EXTRA_CIRCULAR_REVEAL_X, 0);
revealY = intent.getIntExtra(EXTRA_CIRCULAR_REVEAL_Y, 0);
ViewTreeObserver viewTreeObserver = rootLayout.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
revealActivity(revealX, revealY);
rootLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
} else {
rootLayout.setVisibility(View.VISIBLE);
}
}
protected void revealActivity(int x, int y) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float finalRadius = (float) (Math.max(rootLayout.getWidth(), rootLayout.getHeight()) * 1.1);
// create the animator for this view (the start radius is zero)
Animator circularReveal = ViewAnimationUtils.createCircularReveal(rootLayout, x, y, 0, finalRadius);
circularReveal.setDuration(400);
circularReveal.setInterpolator(new AccelerateInterpolator());
// make the view visible and start the animation
rootLayout.setVisibility(View.VISIBLE);
circularReveal.start();
} else {
finish();
}
}
protected void unRevealActivity() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
finish();
} else {
float finalRadius = (float) (Math.max(rootLayout.getWidth(), rootLayout.getHeight()) * 1.1);
Animator circularReveal = ViewAnimationUtils.createCircularReveal(
rootLayout, revealX, revealY, finalRadius, 0);
circularReveal.setDuration(400);
circularReveal.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
rootLayout.setVisibility(View.INVISIBLE);
finish();
}
});
circularReveal.start();
}
}