Layout Flip Animation in Android

Layout Flip Animation in Android

    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

    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 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

    Each side of the "card" layout is a 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
<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>
    And this is "back layout" which contains some texts:
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

    Create 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

    Now, you'll need to display the 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
<?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>
    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:
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();
            }
        });
    }
}
    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 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.
This is the remaining code of 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!

Conclusions

    By adding animation to fragments transaction process, we now able to make a card flip animation easily. Hope this trick is helpful with your own work. Further, you can visit this tag link to read all posts about creating animation in Android. Finally, you can download full source code by click the button below!


    References to original post on Android Developer blog.
Androip Tip: create Digital Rain Effect (Matrix Effect)

Androip Tip: create Digital Rain Effect (Matrix Effect)

    You must be familiar with Matrix Effect which has green codes float on black screen (very popular in Matrix film series). In Android, Matrix Effect has been implemented in various applications often as a Live Wallpaper. Through this tip, I would like to present a type of Matrix Effect called Digital Rain Effect - the codes is falling and like rain tears represents the activity of the virtual reality environment.

Custom Matrix effect class

    We will create a custom view based on View class. Firstly, we define some variables for the Digital Rain Effect with the size of the code, the size of a column, the position of the bottom text for each column and then the characters that will be used for the code (I will use only alphabet chars). Note that you can put the characters you want here or why not a custom font:
public class MatrixEffect extends View {

    private static Random random;
    private int width, height;
    private Canvas canvas;
    private Bitmap canvasBmp;
    private int fontSize = 40;
    private int columnSize;
    private char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWSYZabcdefghijklmnopqrstuvwyz".toCharArray();
    private int[] txtPosByColumn;
    private Paint paintTxt, paintBg, paintBgBmp, paintInitBg;
}
    Now, in the constructor, we'll initialize all Paint variables, which define that the text (running code) color is green, the background is black. You also need to create a new Random object here (to random text codes later):
public MatrixEffect(Context context, AttributeSet attrs) {
        super(context, attrs);
        random = new Random();

        paintTxt = new Paint();
        paintTxt.setStyle(Paint.Style.FILL);
        paintTxt.setColor(Color.GREEN);
        paintTxt.setTextSize(fontSize);

        paintBg = new Paint();
        paintBg.setColor(Color.BLACK);
        paintBg.setAlpha(5);
        paintBg.setStyle(Paint.Style.FILL);

        paintBgBmp = new Paint();
        paintBgBmp.setColor(Color.BLACK);

        paintInitBg = new Paint();
        paintInitBg.setColor(Color.BLACK);
        paintInitBg.setAlpha(255);
        paintInitBg.setStyle(Paint.Style.FILL);
    }
    To get view width and height, we override the onSizeChanged() method of the View class. We initialize the position of the first character for each column. We use a random position between the top of the screen and the middle of the screen and save in the txtPosByColumn array:
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width = w;
        height = h;

        canvasBmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        canvas = new Canvas(canvasBmp);
        canvas.drawRect(0, 0, width, height, paintInitBg);
        columnSize = width / fontSize;

        txtPosByColumn = new int[columnSize + 1];

        for (int x = 0; x < columnSize; x++) {
            txtPosByColumn[x] = random.nextInt(height / 2) + 1;
        }
    }
    Finally, we override the onDraw() of our custom view, call the drawCanvas method and invalidate the view to force a redraw. With that call, the Matrix Effect could progress from top to bottom in infinite mode. Inside drawCanvas(), call drawText() method used to draw a random character for each column at the position indicated by txtPosByColumn variable above:
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(canvasBmp, 0, 0, paintBgBmp);
        drawCanvas();
        invalidate();
    }

    private void drawText() {
        for (int i = 0; i < txtPosByColumn.length; i++) {
            canvas.drawText("" + chars[random.nextInt(chars.length)], i * fontSize, txtPosByColumn[i] * fontSize, paintTxt);

            if (txtPosByColumn[i] * fontSize > height && Math.random() > 0.975) {
                txtPosByColumn[i] = 0;
            }
            txtPosByColumn[i]++;
        }
    }

    private void drawCanvas() {
        canvas.drawRect(0, 0, width, height, paintBg);
        drawText();
    }

Usage in Activity/Fragment

    In order to use this view, please declaring a MatrixEffectView in your activity/fragment layout (XML) file:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="info.devexchanges.androidmatrixeffect.MainActivity">

    <info.devexchanges.androidmatrixeffect.MatrixEffectView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>
    And there is no special point in your activity programmatically code, just need setContentView():
MainActivity.java
package info.devexchanges.androidmatrixeffect;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
    You may have this output when running this application:



References: from original post in Ssaurel's blog.
Android Tip: Type Writer Animation

Android Tip: Type Writer Animation

    Meaningful animations always make our application more exciting and friendly. So, in the development work, you should pay attention to this topic. Android SDK supports us a lot in building the our own animations, sometimes just a few simple steps in code.
   In this tip, you’re going to learn how to create a Type Writer Effect in Android. Like you’re going to see, it’s really easy to create this cool effect on Android by creating a subclass of the TextView component (make a custom view) and by using a Handler and it's postDelayed() method.


Creating a custom TextView

    I named this class is TypeWriterTextView, it will extend from TextView. All you need is combining a Handler with a Runnable that is used to type each letter of the text to display at some defined delay by calling the postDelayed() method of the Handler object:
TypeWriterTextView.java
package info.devexchanges.typewriteranimation;

import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.widget.TextView;

public class TypeWriterTextView extends TextView {

    private CharSequence sequence;
    private int mIndex;
    private long delay = 150; //default is 150 milliseconds

    public TypeWriterTextView(Context context) {
        super(context);
    }

    public TypeWriterTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    private Handler handler = new Handler();
    private Runnable runnable = new Runnable() {

        @Override
        public void run() {
            setText(sequence.subSequence(0, mIndex++));
            if (mIndex <= sequence.length()) {
                handler.postDelayed(runnable, delay);
            }
        }
    };

    /**
     * Display text with type writer animation
     * @param txt content will be displayed
     */
    public void displayTextWithAnimation(CharSequence txt) {
        sequence = txt;
        mIndex = 0;

        setText("");
        handler.removeCallbacks(runnable);
        handler.postDelayed(runnable, delay);
    }

    /**
     * Change the delay value with this method
     * @param m
     */
    public void setCharacterDelay(long m) {
        delay = m;
    }
}

Declaring in activity layout

    In order to use it, just put a TypeWriterTextView object to activity layout (XML) file like this:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="info.devexchanges.typewriteranimation.MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="@string/button" />

    <info.devexchanges.typewriteranimation.TypeWriterTextView
        android:id="@+id/text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textSize="20sp" />
</RelativeLayout>

Start animation in activity programmatically code

    Nothing special at the activity Java code, we have just to start the animation by calling the displayTextWithAnimation() method of our TypeWriterTextView implementation:
MainActivity.java
package info.devexchanges.typewriteranimation;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        final TypeWriterTextView animationText = (TypeWriterTextView) findViewById(R.id.text_view);
        Button btnStartAnimation = (Button) findViewById(R.id.button);

        //Start animation in TextView after click
        btnStartAnimation.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                animationText.setText("");
                animationText.setCharacterDelay(160);
                animationText.displayTextWithAnimation(getString(R.string.lorem_ipsum));
            }
        });

    }
}

Output when running

    After launching the app, you'll have this output:

Final thoughts

    As you can see, by making a custom view from TextView, we now have type writer animation in our UI. Moreover, you can visit this tag link to read all posts about Android animation on my blog.
    Reference: Original post from Ssaurel Blog.
Android Tip: Synchronously Animating Toolbar, TabLayout, and StatusBar Background Colors

Android Tip: Synchronously Animating Toolbar, TabLayout, and StatusBar Background Colors

    As you can see on Google Play application, when you change selected tab on the main screen (which has 2 tabs: App & Game and Books), the TabLayout, Toolbar and Status bar background color are also changed with an animation. This effect is look like this:

    By using TabLayout widget of Design Support Library, we can make this effect easily.
    Basically, within the onTabSelected() method of my TabLayout.OnTabSelectedListener implementation, I wanted to animate from the current color to the new tab’s corresponding color, ensuring that all views are animating simultaneously. Call this interface through addOnTabSelectedListener():
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                //Add more code in this method later
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
    To do this, I chose to use the ValueAnimator which allows you to iterate over the difference of two values over a timed interval. I also used an ArgbEvaluator for the ValueAnimator’s evaluator to handle the calculation of each animation step between the two ARGB colors:
int colorFrom = ((ColorDrawable) toolbar.getBackground()).getColor();
int colorTo = getColorForTab(tab.getPosition());
    We use the toolbar’s current background color as the starting color of the animation, and determine the color to animate to based on the newly selected tab.
    Now the ValueAnimator can be used to inform us of what color to use during each animation iteration:
colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animator) {
                        int color = (int) animator.getAnimatedValue();

                        toolbar.setBackgroundColor(color);
                        tabLayout.setBackgroundColor(color);

                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                            getWindow().setStatusBarColor(color);
                        }
                    }

                });
colorAnimation.start();
    In order to setting the animation duration, you can use this code before call colorAnimation.start():
colorAnimation.setDuration(1000); //time in milliseconds
Finally, we have full code for this main activity:
MainActivity.java
package info.devexchanges.synchronouslycolor;

import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;

public class MainActivity extends AppCompatActivity {

    private TabLayout tabLayout;
    private Toolbar toolbar;
    private String[] colors = {"Red", "Blue", "Green", "Yellow", "Gray"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tabLayout = (TabLayout) findViewById(R.id.tab_layout);
        toolbar = (Toolbar) findViewById(R.id.toolbar);

        setSupportActionBar(toolbar);

        for (String color : colors) {
            tabLayout.addTab(tabLayout.newTab().setText(color));
        }

        tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
        tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                int colorFrom = ((ColorDrawable) toolbar.getBackground()).getColor();
                int colorTo = getColorForTab(tab.getPosition());

                ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
                colorAnimation.setDuration(1000);
                colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animator) {
                        int color = (int) animator.getAnimatedValue();

                        toolbar.setBackgroundColor(color);
                        tabLayout.setBackgroundColor(color);

                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                            getWindow().setStatusBarColor(color);
                        }
                    }

                });
                colorAnimation.start();
                toolbar.setTitle(colors[tab.getPosition()].toUpperCase());
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });
    }

    public int getColorForTab(int position) {
        if (position == 0) return ContextCompat.getColor(this, R.color.colorPrimary);
        else if (position == 1) return ContextCompat.getColor(this, R.color.blue);
        else if (position == 2) return ContextCompat.getColor(this, R.color.green);
        else if (position == 3) return ContextCompat.getColor(this, R.color.yellow);
        else return ContextCompat.getColor(this, R.color.gray);
    }
}
    And that’s all there is to it - we now have a good animation, make our app look more smoothly and prettier! This is full screen output:

    References:

Meaningful motion for Activities transition in Android Lollipop

    As we can see at Material Design specs:
Motion in the world of material design is used to describe spatial relationships, functionality, and intention with beauty and fluidity. Motion design can effectively guide the user’s attention in ways that both inform and delight. Use motion to smoothly transport users between navigational contexts, explain changes in the arrangement of elements on a screen, and reinforce element hierarchy.
    From API 21, Material Design has bring us the new way to switch Activity (activity transition) with animations and of course, the element located on these screen are also affected by this transition process.
    We must apply those animations carefully to avoid the app become a true Pixar animation movie. In this post, I will present some customizing of Material meaningful motion, make our application look smoothly.
    DEMO VIDEO:

Prerequisites

    In order to custom activity transition and other related animations, make sure that your min-sdk of your project is 21 or higher. I also add some necessary dependencies which use for my sample project later:
app/build.gradle
apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.2"

    defaultConfig {
        applicationId "info.devexchanges.uimotion"
        minSdkVersion 21
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:24.2.0'
    compile 'com.android.support:design:24.2.0'
    compile 'com.android.support:gridlayout-v7:24.2.0'
    compile 'com.android.support:cardview-v7:24.2.0'
}

Custom Activity Transitions in xml

    Before Android Lollipop (API Level 21) we could only customize the activity transition animation over entire activity. All views were animated together. But now we can specify how each view is animated during that transition.
    Suppose I have 3 activities: the first called MainActivity which display 3 pictures and after click at any one, app will redirect user to second activity to show selected picture descriptions (called DetailsActivity). This activity contains a FloatingActionButton, when click on it, a translucent activity (SharingActivity) appears which give some options to shared the content. It has a yellow shape which is a drawable defined as image source of a ImageView. Now, we'll custom some animations based on xml resources.
    Create a folder named transaction in res directory, all animations xml files will put here.
    We can specify custom animations for enter and exit transitions and for transitions of shared elements between activities.
  • An enter transition determines how views move into the initial scene of the started activity. 
  • An exit transition determines how views move out of the scene when starting a new activity. 
  • A shared elements transition determines how views are shared between two activities transition.
These are all xml files that defining animation for transacting from MainActivity to DetailsActivity: and showing translucent SharingActivity:
main_reenter.xml
<?xml version="1.0" encoding="utf-8"?>
<slide xmlns:android="http://schemas.android.com/apk/res/android"
    android:slideEdge="top">
    <targets>
        <target android:excludeId="@android:id/statusBarBackground" />
        <target android:excludeId="@android:id/navigationBarBackground" />
    </targets>
</slide>
main_exit.xml
<?xml version="1.0" encoding="utf-8"?>
<explode xmlns:android="http://schemas.android.com/apk/res/android">
    <targets>
        <target android:excludeId="@android:id/statusBarBackground" />
        <target android:excludeId="@android:id/navigationBarBackground" />
    </targets>
</explode>
detail_enter.xml
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
               android:transitionOrdering="together">

    <slide
        android:slideEdge="bottom">
        <targets>
            <target android:targetId="@id/cardview"/>
        </targets>
    </slide>
    <fade>
        <targets>
            <target android:excludeId="@android:id/statusBarBackground"/>
            <target android:excludeId="@android:id/navigationBarBackground"/>
            <target android:excludeId="@id/cardview"/>
        </targets>
    </fade>

</transitionSet>
sharing_shared_element_enter.xml
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
               android:interpolator="@android:interpolator/accelerate_decelerate">
    <changeBounds/>
    <arcMotion
        android:maximumAngle="90"
        android:minimumHorizontalAngle="90"
        android:minimumVerticalAngle="0"/>
</transitionSet>
sharing_item_chosen.xml
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
    <changeBounds/>
    <fade>
        <targets>
            <target android:excludeId="@id/content_root"/>
        </targets>
    </fade>
    <changeImageTransform android:startDelay="@android:integer/config_mediumAnimTime"/>
</transitionSet>
    Activity transition definitions can be declared into theme style and our res/values/styles.xml contains all this:
styles.xml
<resources>

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="AppTheme.Main">
        <item name="android:windowExitTransition">@transition/main_exit</item>
        <item name="android:windowReenterTransition">@transition/main_reenter</item>
    </style>

    <style name="AppTheme.Detail">
        <item name="android:windowTranslucentStatus">true</item>
        <item name="android:windowAllowEnterTransitionOverlap">false</item>
        <item name="android:windowEnterTransition">@transition/detail_enter</item>
    </style>

    <style name="AppTheme.Sharing">
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowBackground">@color/black</item>
        <item name="android:windowTranslucentStatus">true</item>
        <item name="android:windowSharedElementEnterTransition">@transition/sharing_shared_element_enter</item>
    </style>

    <style name="ShareItemView">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:background">?android:attr/selectableItemBackgroundBorderless</item>
        <item name="android:textAppearance">@style/TextAppearance.AppCompat.Medium.Inverse</item>
    </style>

</resources>
    And never forget to use the correct theme for each activity in AndroidManifest.xml:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="info.devexchanges.uimotion">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme.Main">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".DetailsActivity"
            android:theme="@style/AppTheme.Detail"/>
        <activity android:name=".SharingActivity"/>
    </application>

</manifest>

Transition from Main screen to Detail screen

    When user clicks on some image item, we must start the DetailsActivity with some information that indicates we’re starting a Customized Activity Transition. In MainActivity we have:
    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.rose) {
            openDetailActivity(R.drawable.rose, "Rose", view);
        } else if (view.getId() == R.id.sunflower) {
            openDetailActivity(R.drawable.sunflower, "Sunflower", view);
        } else {
            openDetailActivity(R.drawable.tulip, "Tulip", view);
        }
    }

    private void openDetailActivity(int drawable, String title, View view) {
        ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, view, getString(R.string.picture_transition_name));
        Intent intent = new Intent(this, DetailsActivity.class);
        intent.putExtra(DetailsActivity.EXTRA_DRAWABLE, drawable);
        intent.putExtra(DetailsActivity.EXTRA_TITLE, title);

        startActivity(intent, options.toBundle());
    }
    The most important method is ActivityOptions.makeSceneTransitionAnimation(). It create an object containing information about our scene transition animation.
    As you see, I pass drawable id and string title  from MainActivity to setup  CollapsingToolbarLayout and ImageView in DetailsActivity. To finish the our motion from main to details screen we just scale up the share button when the transition is ended:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_details);
        setSupportActionBar((Toolbar) findViewById(R.id.toolbar));

        int drawable = getIntent().getExtras().getInt(EXTRA_DRAWABLE);
        CharSequence title = getIntent().getExtras().getCharSequence(EXTRA_TITLE);

        CollapsingToolbarLayout collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
        collapsingToolbarLayout.setTitle(title);

        ImageView pictureView = (ImageView) findViewById(R.id.picture);
        pictureView.setImageResource(drawable);
        pictureView.setContentDescription(title);

        btnShare = findViewById(R.id.btn_share);
        textView = (TextView) findViewById(R.id.text);

        if (drawable == R.drawable.rose) {
            textView.setText(getString(R.string.rose));
        } else if (drawable == R.drawable.tulip) {
            textView.setText(getString(R.string.tulip));
        } else textView.setText(getString(R.string.sunflower));

        if (savedInstanceState == null) {
            btnShare.setScaleX(0);
            btnShare.setScaleY(0);
            getWindow().getEnterTransition().addListener(new TransitionAdapter() {
                @Override
                public void onTransitionEnd(Transition transition) {
                    getWindow().getEnterTransition().removeListener(this);
                    btnShare.animate().scaleX(1).scaleY(1);
                }
            });
        }
    }
    But if we are scaling up the share button when the Activity is opened then we have to scale down when the activity is finished:
    @Override
    public void onBackPressed() {
        btnShare.animate().scaleX(0).scaleY(0).setListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                supportFinishAfterTransition();
            }
        });
    }
    And when running app, we have this output:

Transition from Detail screen to Sharing screen

    Launching SharingActivity after click on the FloatingActionButton:
btnShare.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(DetailsActivity.this,
                        btnShare, getString(R.string.share_transition_name));
                Intent intent = new Intent(DetailsActivity.this, SharingActivity.class);
                startActivity(intent, options.toBundle());
            }
        });
    In SharingActivity, we have to setup initial states before the animation begin:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        rootView = (ViewGroup) findViewById(R.id.content_root);
        backgroundView = (ImageView) findViewById(R.id.background);
        btnFacebook = findViewById(R.id.facebook);
        btnInstagram = findViewById(R.id.instagram);
        btnTwitter = findViewById(R.id.twitter);
        btnGoogle = findViewById(R.id.google_plus);

        if (savedInstanceState == null) {
            // Setup initial states
            backgroundView.setVisibility(View.INVISIBLE);
            btnGoogle.setAlpha(0);
            btnTwitter.setAlpha(0);
            btnFacebook.setAlpha(0);
            btnInstagram.setAlpha(0);
        }

        getWindow().getSharedElementEnterTransition().addListener(new TransitionAdapter() {
            @Override
            public void onTransitionEnd(Transition transition) {
                getWindow().getSharedElementEnterTransition().removeListener(this);
                revealTheBackground();
                showTheItems();
            }
        });

        ...
    }
    The main work in SharingActivity is handling share items (buttons) click. The pure Transition Framework was added since Android API 19. This framework animates the views at runtime by changing some of their property values over time. One of the features is the ability of running animations based on the changes between starting and ending view property values:
    @Override
    public void onClick(View view) {
        showToast(view.getId());
        // Load the transition
        Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.sharing_item_chosen);
        // Finish this Activity when the transition is ended
        transition.addListener(new TransitionAdapter() {
            @Override
            public void onTransitionEnd(Transition transition) {
                finish();
                // Override default transition to fade out
                overridePendingTransition(0, android.R.anim.fade_out);
            }
        });
        // Capture current values in the scene root and then post a request to run a transition on the next frame
        TransitionManager.beginDelayedTransition(rootView, transition);

        // 1. Item chosen
        RelativeLayout.LayoutParams layoutParams =
                new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
        view.setLayoutParams(layoutParams);

        // 2. Rest of items
        View[] itemViews = {btnFacebook, btnInstagram, btnTwitter, btnGoogle};
        for (View itemView : itemViews) {
            if (itemView != view) {
                itemView.setVisibility(View.INVISIBLE);
            }
        }

        // 3. Background
        double diagonal = Math.sqrt(rootView.getHeight() * rootView.getHeight() + rootView.getWidth() * rootView.getWidth());
        float radius = (float) (diagonal / 2f);
        int h = backgroundView.getDrawable().getIntrinsicHeight();
        float scale = radius / (h / 2f);
        Matrix matrix = new Matrix(backgroundView.getImageMatrix());
        matrix.postScale(scale, scale, backgroundView.getWidth() / 2f, backgroundView.getHeight() / 2f);
        backgroundView.setScaleType(ImageView.ScaleType.MATRIX);
        backgroundView.setImageMatrix(matrix);
    }
    Moreover, override onBackPressed() to start the hide animation of item and background:
private void hideTheBackground() {
        Animator hide = createRevealAnimator(false);
        hide.setStartDelay(defaultAnimDuration);
        hide.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                backgroundView.setVisibility(View.INVISIBLE);
                supportFinishAfterTransition();
            }
        });
        hide.start();
    }

    @Override
    public void onBackPressed() {
        hideTheItems();
        hideTheBackground();
    }

    private void hideTheItems() {
        View[] itemViews = {btnFacebook, btnInstagram, btnTwitter, btnGoogle};
        for (int i = 0; i < itemViews.length; i++) {
            View itemView = itemViews[i];
            long startDelay = (defaultAnimDuration / itemViews.length) * (itemViews.length - i);
            itemView.animate().alpha(0).setStartDelay(startDelay);
        }
    }
    And we'll have this result:

Final thoughts

    I have presented a simple project about applying motion in our application to avoid a bad User Experience. In this sample app, we saw how to build beautiful apps with meaningful and delightful motion. And below are some links where you can go deeper into Android Motion:

Expanding/Collapsing RecyclerView row smoothly with Animation in Android

    As you can see, I had a post about this topic: creating expansible/collapsible layout with animation by using a third-party library and apply it as list view row to show more/hide apart item details. Basically, like another libraries, it work very well and this is the best solution. But, by another way, you can use Animation and AnimationUtils in Android SDK, declaring your animations from your own xml files.
    In this post, I will present this way to create an expandable layout with animation and apply it as a RecyclerView row.

Creating animation from xml file

    Create an xml file which defines type of animation to perform. This file should be located under anim folder under res directory. If you don’t have anim folder in your res directory create one.
    Because of these are expanding and collapsing animations, so I have 2 xml files called slide_down.xml and slide_up.xml.
   Sliding animation uses <scale> tag only. Slide down is exactly opposite to slide down (expanding) animation. Just interchange android:fromYScale and android:toYScale values:
slide_down.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true">

    <scale
        android:duration="500"
        android:fromXScale="1.0"
        android:fromYScale="0.0"
        android:interpolator="@android:anim/linear_interpolator"
        android:toXScale="1.0"
        android:toYScale="1.0" />

</set>
Slide up can be achieved by setting android:fromYScale="1.0" and android:toYScale="0.0":
slide_up.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true" >

    <scale
        android:duration="500"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:interpolator="@android:anim/linear_interpolator"
        android:toXScale="1.0"
        android:toYScale="0.0" />

</set>

Usage in Activity

    With Animation and AnimationUtils, we can create an animation for our layout easily. Suppose we have this activity layout:
activity_ex_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/content_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/holo_green_dark"
        android:clickable="true"
        android:onClick="toggle_contents"
        android:padding="10dp"
        android:text="@string/title"
        android:textColor="@android:color/white" />

    <!--content to hide/show -->
    <TextView
        android:id="@+id/title_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/holo_blue_dark"
        android:padding="10dp"
        android:text="@string/long_content"
        android:textColor="@android:color/white" />

</LinearLayout>
    And we have this activity Java code:
ExpandableLayoutActivity.java
package info.devexchanges.expandablelayout;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.TextView;

public class ExpandableLayoutActivity extends AppCompatActivity {

    private TextView txtContent;
    private Animation animationUp;
    private Animation animationDown;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ex_layout);

        txtContent = (TextView) findViewById(R.id.title_text);
        TextView txtTitle = (TextView) findViewById(R.id.content_text);
        txtContent.setVisibility(View.GONE);

        animationUp = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide_up);
        animationDown = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide_down);

        txtTitle.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(txtContent.isShown()){
                    txtContent.setVisibility(View.GONE);
                    txtContent.startAnimation(animationUp);
                }
                else{
                    txtContent.setVisibility(View.VISIBLE);
                    txtContent.startAnimation(animationDown);
                }
            }
        });
    }
}
    Running this activity, we'll have this output:

Use as a RecyclerView row

    As applying these animations in each RecyclerView row, there are some problems with this widget structure, the collapsing animation will not work if you only call setVisibility(GONE) and startAnimation(animationUp) continuously like above, the layout will gone immediately and we won't see the animation. To avoid this matter, providing a CountdownTimer and gone the view when it finished:

holder.contentLayout.startAnimation(animationUp);
CountDownTimer countDownTimerStatic = new CountDownTimer(COUNTDOWN_RUNNING_TIME, 16) {
                        @Override
                        public void onTick(long millisUntilFinished) {
                        }

                        @Override
                        public void onFinish() {
                            holder.contentLayout.setVisibility(View.GONE);
                        }
                    };
                    countDownTimerStatic.start();
    Our RecyclerView adapter is simple like this:
RecyclerAdapter.java
package info.devexchanges.expandablelayout;

import android.content.Context;
import android.os.CountDownTimer;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.widget.ImageView;
import android.widget.TextView;

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ReyclerViewHolder> {
    private LayoutInflater layoutInflater;
    private Animation animationUp, animationDown;
    private Context context;
    private final int COUNTDOWN_RUNNING_TIME = 500;

    public RecyclerAdapter(Context context, Animation animationUp, Animation animationDown) {
        this.layoutInflater = LayoutInflater.from(context);
        this.animationDown = animationDown;
        this.animationUp = animationUp;
        this.context = context;
    }

    @Override
    public ReyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View item = layoutInflater.inflate(R.layout.item_recycler_view, parent, false);

        return new ReyclerViewHolder(item);
    }

    @Override
    public void onBindViewHolder(final ReyclerViewHolder holder, int position) {
        if (position % 3 == 0) {
            holder.image.setImageResource(R.drawable.girl_1);
        } else if (position % 3 == 1) {
            holder.image.setImageResource(R.drawable.girl_2);
        } else {
            holder.image.setImageResource(R.drawable.girl_3);
        }

        holder.showMore.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (holder.contentLayout.isShown()) {
                    holder.contentLayout.startAnimation(animationUp);

                    CountDownTimer countDownTimerStatic = new CountDownTimer(COUNTDOWN_RUNNING_TIME, 16) {
                        @Override
                        public void onTick(long millisUntilFinished) {
                        }

                        @Override
                        public void onFinish() {
                            holder.contentLayout.setVisibility(View.GONE);
                        }
                    };
                    countDownTimerStatic.start();

                    holder.showMore.setText(context.getString(R.string.show));
                    holder.showMore.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.arrow_down, 0);
                } else {
                    holder.contentLayout.setVisibility(View.VISIBLE);
                    holder.contentLayout.startAnimation(animationDown);

                    holder.showMore.setText(context.getString(R.string.hide));
                    holder.showMore.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.arrow_up, 0);
                }
            }
        });
    }

    @Override
    public int getItemCount() {
        return 10;
    }

    class ReyclerViewHolder extends RecyclerView.ViewHolder {
        private ImageView image;
        private TextView showMore;
        private TextView contentLayout;

        private ReyclerViewHolder(final View v) {
            super(v);

            image = (ImageView) v.findViewById(R.id.image);
            contentLayout = (TextView) v.findViewById(R.id.content);
            showMore = (TextView) v.findViewById(R.id.show_more);
        }
    }
}
Important Note: COUNTDOWN_RUNNING_TIME value must equal with animation duration in our xml file (here is 500 milliseconds).
    Layout for each RecyclerView row:
item_recycler_view.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="6dp">

    <ImageView
        android:id="@+id/image"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:contentDescription="@null"
        android:scaleType="fitXY"
        android:src="@drawable/girl_1" />

    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@+id/image"
        android:padding="10dp"
        android:text="@string/app_name"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/short_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/title"
        android:layout_toRightOf="@+id/image"
        android:paddingLeft="10dp"
        android:text="@string/short_content"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/show_more"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/short_content"
        android:layout_toRightOf="@+id/image"
        android:drawablePadding="5dp"
        android:drawableRight="@drawable/arrow_down"
        android:paddingLeft="10dp"
        android:paddingTop="10dp"
        android:text="@string/show"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/image"
        android:background="@color/colorPrimary"
        android:drawablePadding="5dp"
        android:padding="5dp"
        android:text="@string/long_content"
        android:textColor="@android:color/white"
        android:textStyle="bold"
        android:visibility="gone" />

</RelativeLayout>
    Source code for the activity:
ListViewActivity.java
package info.devexchanges.expandablelayout;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;

public class ListViewActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private Animation animationUp, animationDown;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);

        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(linearLayoutManager);

        animationUp = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide_up);
        animationDown = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide_down);

        RecyclerAdapter recyclerViewAdapter = new RecyclerAdapter(this, animationUp, animationDown);
        recyclerView.setAdapter(recyclerViewAdapter);
    }
}
    Running this activity, we'll have this output:

Final thoughts

    If you are an experienced programmer, you will not like this post because it not work well like the "library way" which I posted a few days ago, you should take a glance! Through this, I hope that readers can learn the way to create animations from xml files and use it in your layouts. The fact that adding animation to VISIBLE/GONE view process in Android is not simple as we think, programmers must have many experiences in animating layout, building animations or vector drawables... Finally, you can get my source code on Github.