http://www.devexchanges.info/2017/03/layout-flip-animation-in-android.html
Sometimes, we would like to build a 2-sides layout with 2 separate contents like playing cards and we can flip/switch them smoothly with animation.
By this tutorial post, I will show you how to do a card flip animation with custom fragment animations. Card flips animate between views of content by showing an animation that emulates a card layout flipping over.
And our output (flip animation) will be like this:
Create the animations for the layout flips. You'll need two animators for when the front of the card animates out and to the left and in and from the left. You'll also need two animators for when the back of the card animates in and from the right and out and to the right. Now, create
Each side of the "card" layout is a
Create
Now, you'll need to display the
Now that you have the front of the card showing, you can show the back of the "card" layout with the flip animation at an appropriate time. Create a method to show the other side of the card that does the following things (this method named
Sometimes, we would like to build a 2-sides layout with 2 separate contents like playing cards and we can flip/switch them smoothly with animation.
By this tutorial post, I will show you how to do a card flip animation with custom fragment animations. Card flips animate between views of content by showing an animation that emulates a card layout flipping over.
And our output (flip animation) will be like this:
Create the animators
animator
folder under res
and add these animation files (XML):
card_flip_left_in.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Before rotating, immediately set the alpha to 0. -->
<objectAnimator
android:valueFrom="1.0"
android:valueTo="0.0"
android:propertyName="alpha"
android:duration="0" />
<!-- Rotate. -->
<objectAnimator
android:valueFrom="-180"
android:valueTo="0"
android:propertyName="rotationY"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:duration="@integer/card_flip_time_full" />
<!-- Half-way through the rotation (see startOffset), set the alpha to 1. -->
<objectAnimator
android:valueFrom="0.0"
android:valueTo="1.0"
android:propertyName="alpha"
android:startOffset="@integer/card_flip_time_half"
android:duration="1" />
</set>
card_flip_left_out.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Rotate. -->
<objectAnimator
android:valueFrom="0"
android:valueTo="180"
android:propertyName="rotationY"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:duration="@integer/card_flip_time_full" />
<!-- Half-way through the rotation (see startOffset), set the alpha to 0. -->
<objectAnimator
android:valueFrom="1.0"
android:valueTo="0.0"
android:propertyName="alpha"
android:startOffset="@integer/card_flip_time_half"
android:duration="1" />
</set>
card_flip_right_in.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Before rotating, immediately set the alpha to 0. -->
<objectAnimator
android:valueFrom="1.0"
android:valueTo="0.0"
android:propertyName="alpha"
android:duration="0" />
<!-- Rotate. -->
<objectAnimator
android:valueFrom="180"
android:valueTo="0"
android:propertyName="rotationY"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:duration="@integer/card_flip_time_full" />
<!-- Half-way through the rotation (see startOffset), set the alpha to 1. -->
<objectAnimator
android:valueFrom="0.0"
android:valueTo="1.0"
android:propertyName="alpha"
android:startOffset="@integer/card_flip_time_half"
android:duration="1" />
</set>
card_flip_right_out.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Rotate. -->
<objectAnimator
android:valueFrom="0"
android:valueTo="-180"
android:propertyName="rotationY"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:duration="@integer/card_flip_time_full" />
<!-- Half-way through the rotation (see startOffset), set the alpha to 0. -->
<objectAnimator
android:valueFrom="1.0"
android:valueTo="0.0"
android:propertyName="alpha"
android:startOffset="@integer/card_flip_time_half"
android:duration="1" />
</set>
Create 2 Fragment views
Fragment
which has a separate layout that can contain any content you want. You'll then use the two layouts in the Fragments
that you'll later animate. The following layout is "front side" which shows an image:
fragment_card_front.xml
And this is "back layout" which contains some texts: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@null"
android:scaleType="fitXY"
android:src="@drawable/android_team" />
</LinearLayout>
fragment_card_back.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#a6c"
android:orientation="vertical"
android:padding="@dimen/activity_horizontal_margin">
<TextView
android:id="@android:id/text1"
style="?android:textAppearanceLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/card_back_title"
android:textColor="#fff"
android:textStyle="bold" />
<TextView
style="?android:textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:lineSpacingMultiplier="1.2"
android:text="@string/card_back_description"
android:textAllCaps="true"
android:textColor="#80ffffff"
android:textStyle="bold" />
</LinearLayout>
Fragments programmatically code
Fragments
classes for the front and back of the "card" layout. These classes return the layouts that you created previously in the onCreateView()
method of each Fragment
. You can then create instances of this Fragment
in the parent Activity
where you want to show the layout:
FrontLayoutFragment.java
package info.devexchanges.animationfliplayout;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class FrontLayoutFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_card_front, container, false);
}
}
BackLayoutFragment.java
package info.devexchanges.animationfliplayout;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class BackLayoutFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_card_back, container, false);
}
}
Animate "Card" layout in the Activity
Fragments
inside of an Activity
. To do this, first create the layout for your Activity
. In my example, I create a RelativeLayout
that I can add Fragments
to later, I also put a Button
inside it to flip this layout with animation when clicked:
activity_main.xml
In the programmatically code, set the content view to be the layout that you just created. It's also good idea to show a default fragment when the activity is created, I will display the front of the "card" layout by default: <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn_flip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:text="Flip Layout" />
</RelativeLayout>
public class MainActivity extends AppCompatActivity implements FragmentManager.OnBackStackChangedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getFragmentManager()
.beginTransaction()
.add(R.id.container, new FrontLayoutFragment())
.commit();
} else {
isShowingBackLayout = (getFragmentManager().getBackStackEntryCount() > 0);
}
getFragmentManager().addOnBackStackChangedListener(this);
View btnFlip = findViewById(R.id.btn_flip);
btnFlip.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
flipCard();
}
});
}
}
flipCard()
and will be invoked when the Button
clicked):- Sets the custom animations that you created earlier for the fragment transitions.
- Replaces the currently displayed fragment with a new fragment and animates this event with the custom animations that you created.
- Adds the previously displayed fragment to the fragment back stack so when the user presses the Back button, the card flips back over.
MainActivity
: private boolean isShowingBackLayout = false;
private void flipCard() {
if (isShowingBackLayout) {
getFragmentManager().popBackStack();
return;
}
isShowingBackLayout = true;
getFragmentManager().beginTransaction()
// Replace the default fragment animations with animator resources representing
// rotations when switching to the back of the card, as well as animator
// resources representing rotations when flipping back to the front (e.g. when
// the system Back button is pressed).
.setCustomAnimations(
R.animator.card_flip_right_in, R.animator.card_flip_right_out,
R.animator.card_flip_left_in, R.animator.card_flip_left_out)
// Replace any fragments currently in the container view with a fragment
// representing the next page (indicated by the just-incremented currentPage
// variable).
.replace(R.id.container, new BackLayoutFragment())
// Add this transaction to the back stack, allowing users to press Back
// to get to the front of the card.
.addToBackStack(null)
.commit();
}
@Override
public void onBackStackChanged() {
isShowingBackLayout = (getFragmentManager().getBackStackEntryCount() > 0);
}
As you can see at the DEMO output above, when the back layout is showing, if user press Back button, the front layout will be inflated. Conversely, app will be closed!
Comments
Post a Comment