I want to implement sliding-layer animation for activity transition as described in material design guidelines.
However, all I could do by now is a simple combination of slide_in and stay animation which doesn't give me a stacked layer kind of effect. How can I achieve it?
My current implementation :
On Activity Start:
activity.overridePendingTransition(R.anim.slide_in_right, R.anim.stay);
On Activity Close:
activity.overridePendingTransition(R.anim.stay, R.anim.slide_out_right);
slide_in_right.xml:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator">
<translate
android:fromXDelta="100%p"
android:toXDelta="0"
android:duration="@android:integer/config_shortAnimTime" />
</set>
slide_out_right.xml:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator">
<translate
android:fromXDelta="0"
android:toXDelta="100%p"
android:duration="@android:integer/config_shortAnimTime" />
</set>
stay.xml:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime"
android:fromYDelta="0%p"
android:toYDelta="0%p" />
I have finally found a solution for this question. It works flawless.
The important components used in this answer:
The solution is to animate the layout of the FrontActivity out before closing the FrontActivity. This is only possible if you use a toolbar integrated in your layout as your action bar!
I will copy my code here. My animation is an activity that slides in front from the bottom, and dissapears again sliding out to the bottom in front of the previous activity. You can easily get this effect in any direction by just altering the animations.
1) Slide FrontActivity in over BackActivity
Just call overridePendingTransition
when starting FrontActivity from BackActivity.
Intent intent = new Intent(activity, FrontActivity.class);
startActivity(intent);
overridePendingTransition(R.anim.slide_in_bottom, 0);
slide_in_bottom.xml
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromYDelta="100%p"
android:toYDelta="0%p"
android:duration="@android:integer/config_mediumAnimTime"
android:interpolator="@android:anim/decelerate_interpolator">
</translate>
2) When going back from FrontActivity to BackActivity, animate the layout from FrontActivity out before you close FrontActivity!
I did this by calling the following method in my onOptionsSelected()
and my onBackPressed()
in FrontActivity
private void animateOut() {
Animation slideAnim = AnimationUtils.loadAnimation(this,R.anim.slide_out_bottom);
slideAnim.setFillAfter(true);;
slideAnim.setAnimationListener(new AnimationListener() {
public void onAnimationStart(Animation paramAnimation) { }
public void onAnimationRepeat(Animation paramAnimation) { }
public void onAnimationEnd(Animation paramAnimation) {
finish();
// if you call NavUtils.navigateUpFromSameTask(activity); instead,
// the screen will flicker once after the animation. Since FrontActivity is
// in front of BackActivity, calling finish() should give the same result.
overridePendingTransition(0, 0);
}
});
BackgroundView.startAnimation(slideAnim);
}
slide_out_bottom.xml
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromYDelta="0%p"
android:toYDelta="100%p"
android:duration="@android:integer/config_mediumAnimTime"
android:interpolator="@android:anim/accelerate_interpolator">
</translate>
3) Now we have to make sure BackActivity is visible behind FrontActivity when it animates out.
We need to work with transparent themes for this.
styles.xml
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- your theme -->
</style>
<style name="Theme.Transparent" parent="AppTheme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
</resources>
4) Apply the transparent theme to FrontActivity in your manifest:
AndroidManifest.xml
<activity
android:name=".FrontActivity"
android:theme="@style/Theme.Transparent"
android:parentActivityName=".BackActivity" />
5) Because your activity is now transparent, you will need to add a background to BackgroundView. The standard backgrounds are:
android:background="@android:color/background_light"
android:background="@android:color/background_dark"
front_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- This is BackgroundView and can be any ViewGroup -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:background="@android:color/background_light" >
<android.support.v7.widget.Toolbar
android:layout_height="@dimen/height_toolbar"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
<!-- rest of layout -->
</FrameLayout>
That's it. The animation should be working now.
EDIT
I have found a solution that doesn't flicker. The animation looks flawless.
When closing FrontActivity, call finish
instead of NavUtils.navigateUpFromSameTask(activity)
. I have changed this in my answer.
You can obtain the described behavior just overriding the transition between activities. I also include a fade-shrink effect on the back activity to improve its appearance:
slide_in_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="100%p" android:toXDelta="0"
android:duration="@android:integer/config_shortAnimTime"/>
</set>
slide_out_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0" android:toXDelta="100%p"
android:duration="@android:integer/config_shortAnimTime"/>
</set>
fade_back.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:duration="@android:integer/config_shortAnimTime"
android:pivotX="50.0%"
android:pivotY="50.0%"
android:fromXScale="1.0"
android:toXScale="0.9"
android:fromYScale="1.0"
android:toYScale="0.9"/>
<alpha android:duration="@android:integer/config_shortAnimTime"
android:fromAlpha="1.0"
android:toAlpha="0.7"/>
</set>
fade_forward.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:duration="@android:integer/config_shortAnimTime"
android:pivotX="50.0%"
android:pivotY="50.0%"
android:fromXScale="0.9"
android:toXScale="1.0"
android:fromYScale="0.9"
android:toYScale="1.0"/>
<alpha android:duration="@android:integer/config_shortAnimTime"
android:fromAlpha="0.7"
android:toAlpha="1.0"/>
</set>
ParentActivity.java
In a parent class common for your activities you can include your reusable code:
/* Activity transitions */
protected void slideInTransition() {
overridePendingTransition(R.anim.slide_in_right, R.anim.fade_back);
}
protected void slideOutTransition() {
overridePendingTransition(R.anim.fade_forward, R.anim.slide_out_right);
}
Then on Activity Start:
startActivity(intent);
slideInTransition();
For back transition:
@Override
public void onBackPressed() {
super.onBackPressed();
slideOutTransition();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With