Android

Android Animated Cards Using Activity Transition

android activity transition
Written by Yasir Ameen

You can create lots of beautiful design for your app using either listview or cardview, you can also apply animation according to your need. One of the greatest enhancement in animation library came into Lollipop API 21 is Activity transition and Shared element transition . In this tutorial i will creat a ListView using the cardview and i implement Activity transition and Shared element transition animation.

 

 

You can see following video in order to see, what we are going to create.

 

dependencies

Following are the dependencies i am using in this project

 dependencies {
   compile fileTree(dir: 'libs', include: ['*.jar'])
   testCompile 'junit:junit:4.12'
   compile 'com.android.support:appcompat-v7:23.3.0'
   compile 'com.android.support:cardview-v7:23.3.0'
   compile 'com.makeramen:roundedimageview:2.2.1'
   compile 'com.squareup.picasso:picasso:2.5.2'
}

Before deep dive into the topic, i would like to tell you some important things.

  • I am using all the movie background image with size of 600×316 compress image.
  • I used picasso libary because i dont want my project to load image slowly.
  • I used circular image library to give all the cover images white border
  • always use uniformly size images, that will not lag your list while scrolling.
  • You can use Fileminimizer tool in order to compress image.
  • I used Batman Vs Superman Big Movie Poster image in DetailsActivity Background 🙂

Let’s Start…

Activity Transition

Material design apps in android also provide visual connection between different stats through motion and transformation between common elements. Meaning that, when you launch Activity B from the Activity A, some transition/animation come into place when leaving/starting /returning to the activities.

Following picture is describing transition when activity changes and back forth.

android activity transition animation

Defining Transition For Activity

You define transition for your activity by creating a folder name transition in your res directory. Just right click on the res folder and choose android resource directory and name the newly directory, transition.

android transition resource directory

Now you are ready to define activity transition. In order to define transition you create a xml file in newly created transition directory, i name the file card_exit.xml

There are some built-in transition you can use.

  • <explode />
  • <changeBounds />
  • <fade />
  • <slide />
  • <autotransition />

In my case in the animated card. I m using <explode /> transition when leaving the activity A to activity B, also i am using some other information to with explode animation such time duration and interpolator, you can just copy and paste the following code for learning purpose.

 <?xml version="1.0" encoding="utf-8"?>
   <transitionSet
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:duration="2500"
     android:interpolator="@android:interpolator/decelerate_quad">
   <explode/>

</transitionSet>

After creating transition we need to specify when the transition should call. In this project “animated card” i will use card_exit.xml when Activity A exit and start Activity B. We can specify these information either in xml or in java. I am using xml.

Open styles.xml from res=>values directory and add following lines in <style name=”AppTheme … >

 

<item name="android:windowContentTransitions">true</item>
<item name="android:windowExitTransition">@transition/card_exit</item>

 

see my styles.xml file snapshot

android enabling window content transition

 

 

Let’s Create Animated Cards

You have create transition, also you have define when it should be use, now its time to create animated cards.

Step 1) Creating Card Template

Create xml file in you res=>layout directory and call it card_item_template.xml , i also attached image for understanding the card design.

Make sure you design your card_template in CardView Widget. I am giving you the boiler plate of card view , you can copy and paste this code and you are ready to create any complex layout in cardview.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="1dp">

    <android.support.v7.widget.CardView
        android:id="@+id/card_view"
        android:layout_gravity="center"
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:elevation="6dp">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            
            //Define Your Layout in CardView Here

        </RelativeLayout>

    </android.support.v7.widget.CardView>
</LinearLayout>


 

Now open card_item_template.xml and paste the following code. [above cardview boiler plate is using here]

important : i used black layer top of background image, layer is made by using View and applying black color as background with alpha property.

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="1dp">

    <android.support.v7.widget.CardView
        android:id="@+id/card_view"
        android:layout_gravity="center"
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:elevation="6dp">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/img_background"
                android:src="@drawable/revenant_bg"
                android:scaleType="centerCrop"
                android:layout_alignParentBottom="true"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:transitionName="selectedMovie"/>

            <View
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="#000000"
                android:alpha=".4"
                android:id="@+id/vw_blacklayer" />

            <com.makeramen.roundedimageview.RoundedImageView
                android:layout_width="80dp"
                android:layout_height="110dp"
                android:id="@+id/img_cover_d"
                android:src="@drawable/bvs"
                android:scaleType="centerCrop"
                app:riv_border_width="2dip"
                app:riv_border_color="#ffffff"
                android:layout_marginBottom="12dp"
                android:layout_alignParentBottom="true"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_marginLeft="13dp"
                android:layout_marginStart="13dp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:text="Batman Vs Superman"
                android:id="@+id/txt_movie_details"
                android:singleLine="true"
                android:layout_marginTop="6dp"
                android:paddingLeft="10dp"
                android:textSize="20sp"
                android:textColor="#ffffff"
                android:layout_alignTop="@+id/img_cover_d"
                android:layout_toRightOf="@+id/img_cover_d"
                android:layout_toEndOf="@id/img_cover_d" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:text="It&apos;s been nearly two years since Superman&apos;s (Henry Cavill) colossal battle with Zod (Michael Shannon) devastated the city of Metropolis."
                android:id="@+id/txt_plot_d"
                android:paddingLeft="10dp"
                android:paddingRight="10dp"
                android:lines="3"
                android:textSize="12sp"
                android:ellipsize="end"
                android:textColor="#ffffff"
                android:layout_below="@+id/txt_movie_details"
                android:layout_toRightOf="@+id/img_cover_d"
                android:layout_toEndOf="@+id/img_cover_d" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:text="o Release date: March 25, 2016"
                android:id="@+id/txt_release_d"
                android:textColor="#ffffff"
                android:layout_marginTop="2dp"
                android:paddingLeft="10dp"
                android:textSize="14sp"
                android:layout_below="@+id/txt_plot_d"
                android:layout_toRightOf="@+id/img_cover_d"
                android:layout_toEndOf="@+id/img_cover_d" />
        </RelativeLayout>

    </android.support.v7.widget.CardView>
</LinearLayout>


 

cardview design

Step 2) Writing DataModel Class

I am using static data for this project. Create a class DataModel.java and paste following arrays.

package yasiramee.com.animatedlistview;

/**
 * Created by YASIR on 5/2/2016.
 */
public class DataModel {

   public static String[] movies = {

           "Batman v Superman",
           "Captain America: Civil War",
           "X-Men: Apocalypse","The Jungle Book",
           "The Legend of Tarzan",
           "The Revenant",
           "Avengers: Age of Ultron"

   };
   public static String[] plot = {

            "It's been nearly two years since Superman's (Henry Cavill) colossal battle with Zod (Michael Shannon) devastated the city of Metropolis.",
            "Political pressure mounts to install a system of accountability when the actions of the Avengers lead to collateral damage. The new status quo deeply divides members of the team.",
            "Worshiped as a god since the dawn of civilization, the immortal Apocalypse (Oscar Isaac) becomes the first and most powerful mutant. Awakening after thousands of years",
            "Raised by a family of wolves since birth, Mowgli (Neel Sethi) must leave the only home he's ever known when the fearsome tiger Shere Khan (Idris Elba) unleashes his mighty roar",
            "Many years after he left Africa behind, Tarzan (Alexander Skarsgård) returns to the Congo to serve as a trade emissary, unaware that he is actually a pawn in a Belgian captain's (Christoph Waltz) deadly plot.",
            "While exploring the uncharted wilderness in 1823, frontiersman Hugh Glass (Leonardo DiCaprio) sustains life-threatening injuries from a brutal bear attack.",
            "When Tony Stark (Robert Downey Jr.) jump-starts a dormant peacekeeping program, things go terribly awry, forcing him, Thor (Chris Hemsworth), the Incredible Hulk (Mark Ruffalo) and the rest of the Avengers to reassemble."

    };

   public static String[] releaseDate = {
           "Release date: March 25, 2016",
           "Release date: May 6, 2016",
           "Release date: May 27, 2016",
           "Release date: April 15, 2016",
           "Release date: July 1, 2016",
           "Release date: December 25, 2015",
           "Release date: May 1, 2015"
   };


    public static int cover[] = {
            R.drawable.bvs,
            R.drawable.civilwar,
            R.drawable.xmen,
            R.drawable.junglebook,
            R.drawable.tarzan,
            R.drawable.revenant,
            R.drawable.ageofultron

    };

    public static int background[] = {
            R.drawable.bvs_bg,
            R.drawable.civilwar_bg,
            R.drawable.xmen_bg,
            R.drawable.junglebk_bg,
            R.drawable.tarzan_bg,
            R.drawable.revenant_bg,
            R.drawable.avengers_bg
    };
}

 

Step 3)Writing MoviesAdapter Class

Now create a adapter for our customize card with he help of above data, create a class and name it MoviesAdapter.java and paste the following code.

public class MoviesAdapter extends BaseAdapter{

    private Context context;
    private LayoutInflater inflater = null;


     MoviesAdapter(Context con, String[] list) {

        this.context = con;
        DataModel.movies = list;
        inflater = LayoutInflater.from(context);
    }


    @Override
    public int getCount() {
        return DataModel.movies.length;
    }

    @Override
    public Object getItem(int i) {
        return DataModel.movies.length;
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View convertview, ViewGroup viewGroup) {
        ViewHolder holder;
        if(convertview == null) {

            convertview =inflater.inflate(R.layout.card_item_template,null);
            holder = new ViewHolder();

            holder._cover = (ImageView) convertview.findViewById(R.id.img_cover_d);
            holder._background = (ImageView) convertview.findViewById(R.id.img_background);
            holder._movies = (TextView) convertview.findViewById(R.id.txt_movie_details);
            holder._plot = (TextView) convertview.findViewById(R.id.txt_plot_d);
            holder._releaseDate = (TextView) convertview.findViewById(R.id.txt_release_d);
            holder._vw_blayer =  convertview.findViewById(R.id.vw_blacklayer);

            convertview.setTag(holder);

        } else {
            holder = (ViewHolder) convertview.getTag();
        }


        holder._movies.setText(DataModel.movies[i]);
        holder._plot.setText(DataModel.plot[i]);
        holder._releaseDate.setText("o "+DataModel.releaseDate[i]);
        //holder._cover.setImageResource(cover[i]);
        Picasso.with(context).load(DataModel.cover[i]).into(holder._cover);
        // holder._background.setImageResource(background[i]);
        Picasso.with(context).load(DataModel.background[i]).into(holder._background);


        ObjectAnimator fade = ObjectAnimator.ofFloat(holder._vw_blayer, View.ALPHA, 1f,.3f);
        fade.setDuration(1500);
        fade.setInterpolator(new LinearInterpolator());
        fade.start();


        return convertview;
    }

    public class ViewHolder {

        ImageView _cover;
        ImageView _background;
        TextView _movies;
        TextView _plot;
        TextView _releaseDate;
        View _vw_blayer;


    }
}

 

Step 4 ) Now open Main_Activity.java and paste following code. I am assuming that you have created a simple layout using listview with a height and width using match-parent attribute

public class MainActivity extends AppCompatActivity {

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

        ListView lv = (ListView) findViewById(R.id.listView);
        MoviesAdapter adapter = new MoviesAdapter(MainActivity.this,DataModel.movies);
        lv.setAdapter(adapter);

    }
}

 

Run the app and click any card. you will see transition animation in your app when MainActivity exits to DetailsActivity, and when you click back, you will also see slide animation when MainActivity reenter from DetailsActivity

run the app and you will see some fade animation on individual card when you scroll.

android customize listview with cards

Creating Details Activity With Animation.

You  are done with scroll able cards also with a fade animation, now its time to implement Activity transition. In this section we create a detail Activity, when we click on any card, our scroll able list will animate and will open Detail Activity with floating card animation.

Step 1) Creating and designing DetailsActivity

Create new Activity in your project and call it DetailsActivity. We will open this activity when someone click on any card from the MainActivity, but first open activity_details.xml and paste the following xml code. In the following xml i create a DetailsActiviy layout.

important : use cardview widget here for creating detailsActivity. Use boiler plate here i mentioned above.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/batman_vs_sup_full"
    android:gravity="center">

    <android.support.v7.widget.CardView
        android:id="@+id/card_view"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_width="match_parent"
        android:layout_height="480dp"
        android:elevation="4dp"
        card_view:cardCornerRadius="8dp">

        <RelativeLayout
            android:id="@+id/rel_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:scaleType="centerCrop"
                android:src="@drawable/revenant_bg"
                android:id="@+id/cover_bg_details"
                android:transitionName="selectedMovie"/>

            <View
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:background="#000000"
                android:alpha="0.3" />

            <com.makeramen.roundedimageview.RoundedImageView
                android:layout_width="70dp"
                android:layout_height="100dp"
                android:src="@drawable/revenant"
                android:scaleType="centerCrop"
                app:riv_border_width="2dip"
                app:riv_border_color="#ffffff"
                android:layout_marginStart="14dp"
                android:id="@+id/cover_details"
                android:layout_alignParentTop="true"
                android:layout_alignParentStart="true"
                android:layout_marginTop="157dp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:text="The Revenant"
                android:id="@+id/txt_movie_details"
                android:singleLine="true"
                android:layout_marginLeft="10dp"
                android:textSize="20sp"
                android:textColor="#ffffff"
                android:layout_alignBottom="@+id/cover_bg_details"
                android:layout_toEndOf="@+id/cover_details"
                android:layout_marginBottom="10dp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:text="&quot;While exploring the uncharted wilderness in 1823, frontiersman Hugh Glass (Leonardo DiCaprio) sustains life-threatening injuries from a brutal bear attack."
                android:id="@+id/txt_plot_details"
                android:layout_marginLeft="10dp"
                android:paddingRight="10dp"
                android:textSize="12sp"
                android:layout_marginTop="5dp"
                android:layout_below="@+id/cover_bg_details"
                android:layout_toEndOf="@+id/cover_details"
                />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:text="WWW.YASIRAMEEN.COM"
                android:id="@+id/textView"
                android:layout_alignParentBottom="true"
                android:layout_centerHorizontal="true"
                android:layout_marginBottom="24dp" />


        </RelativeLayout>

    </android.support.v7.widget.CardView>
</RelativeLayout>

 

above xml code will produce following result.

 

android detail activity with cardview

 

 

Step 2) Starting Detail Activity With Animation

you have applied transition in transition directory, now its time to use these animation effects. I assuming you have create card_exit.xml in res=>transition directory and you have enable window content transition and  activity enter transition in res=>style directory, if you did not, please go above and apply activity transition.

Now open MainActivity.java and modify its code with the following, just copy and paste the code if you are following me in this tutorial.

 

public class MainActivity extends AppCompatActivity {

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


        ListView lv = (ListView) findViewById(R.id.listView);
        MoviesAdapter adapter = new MoviesAdapter(MainActivity.this,DataModel.movies);
        lv.setAdapter(adapter);

        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {

                //We are passing Bundle to activity, these lines will animate when we laucnh activity
                Bundle bundle = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this,
                        Pair.create(view,"selectedMovie")
                        ).toBundle();

                Intent intent = new Intent(MainActivity.this,DetailsActivity.class);
                intent.putExtra("bg",DataModel.background[i]);
                intent.putExtra("cover",DataModel.cover[i]);
                intent.putExtra("title",DataModel.movies[i]);
                intent.putExtra("plot",DataModel.plot[i]);
                startActivity(intent,bundle);

            }
        });
    }
}

 

 Step 3) Writing Functionality of DetailsActivity With Animation

In order to animate card in your detailsActivity, as i showed you in above video, you need to use ObjectAnimator object with animation property of ofFloat. As you see in video, detailsActivity card and moviecover is animating, see code here it is very easy.

//These are lines helping Details_Card To Animate
//===============================================
AnimatorSet animationSet = new AnimatorSet();

//Translating Details_Card in Y Scale
        ObjectAnimator card_y = ObjectAnimator.ofFloat(cardView, View.TRANSLATION_Y, 70);
        card_y.setDuration(2500);
        card_y.setRepeatMode(ValueAnimator.REVERSE);
        card_y.setRepeatCount(ValueAnimator.INFINITE);
        card_y.setInterpolator(new LinearInterpolator());

//Translating Movie_Cover in Y Scale
        ObjectAnimator cover_y = ObjectAnimator.ofFloat(movie_cover, View.TRANSLATION_Y, 30);
        cover_y.setDuration(3000);
        cover_y.setRepeatMode(ValueAnimator.REVERSE);
        cover_y.setRepeatCount(ValueAnimator.INFINITE);
        cover_y.setInterpolator(new LinearInterpolator());

        animationSet.playTogether(card_y,cover_y);
        animationSet.start();

 

isn’t it easy enough ?? now use animation in detailAcitivity. Open DetailsActivity.java and paste following code.

important : keep in mind when we are starting DetailsActivity, we are passing some extras information, we use these extras in DetailsActivity by calling Intent intent = getIntent().

 

public class DetailsActivity extends AppCompatActivity {

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

        Intent intent = getIntent();
        CardView cardView = (CardView) findViewById(R.id.card_view);
        ImageView movie_cover = (ImageView) findViewById(R.id.cover_details);
        TextView movie = (TextView) findViewById(R.id.txt_movie_details);
        ImageView movie_bg = (ImageView) findViewById(R.id.cover_bg_details);
        TextView plot = (TextView) findViewById(R.id.txt_plot_details);


        //These are lines helping Details_Card To Animate
        //===============================================
        AnimatorSet animationSet = new AnimatorSet();

        //Translating Details_Card in Y Scale
        ObjectAnimator card_y = ObjectAnimator.ofFloat(cardView, View.TRANSLATION_Y, 70);
        card_y.setDuration(2500);
        card_y.setRepeatMode(ValueAnimator.REVERSE);
        card_y.setRepeatCount(ValueAnimator.INFINITE);
        card_y.setInterpolator(new LinearInterpolator());

        //Translating Movie_Cover in Y Scale
        ObjectAnimator cover_y = ObjectAnimator.ofFloat(movie_cover, View.TRANSLATION_Y, 30);
        cover_y.setDuration(3000);
        cover_y.setRepeatMode(ValueAnimator.REVERSE);
        cover_y.setRepeatCount(ValueAnimator.INFINITE);
        cover_y.setInterpolator(new LinearInterpolator());

        animationSet.playTogether(card_y,cover_y);
        animationSet.start();


        Picasso.with(this).load(intent.getIntExtra("bg",1)).into(movie_bg);
        Picasso.with(this).load(intent.getIntExtra("cover",1)).into(movie_cover);
        movie.setText(intent.getStringExtra("title"));
        plot.setText(intent.getStringExtra("plot"));

    }
}

Understanding Shared Element Transition

when we want to share same views such as imageView in other with activity with smooth transition, the changeImageTransform shared element transition translates and scales the image smoothly between these activities.

android shared element transitionImplementing Shared Element Transition on ImageView

In the video  i attached above, when click on the card, MainActivity exits with <explode /> transition and background Image of card travel through to to the DetailsActivity.

Open details_activity.xml, in a ImageView where i am showing background image, just add one attribute more and you are done.

android shared element name

android:transitionName attribute is work like an id when we launch activity, this attribute specify which element should be share in Activity Transition.

and this is how you use shared element transitionName in ActivityOption when we launch activity

important : don’t type mention code in picture, its just for giving you a concept that how to use shared element,

android shared element activity option

Now you are ready to run your app and enjoy.
Please ask if you have any query also if you see something is missing and wrong. please let me know 🙂

 

About the author

Yasir Ameen

I'm a programmer, teacher, and speaker. I work out of my home in Pakistan, Karachi for the Mobile, especially Android Platform. I discuss about technology, gadgets, codes, the devices we’re going and we’ve been. I’m excited about community, social equity, and media.

31 Comments

Leave a Comment