Android Shared Element Transition Animation

Filed Under: Android

In this tutorial we’ll implement a different kind of animation transition namely Shared Element Transition between activities.

Android Shared Element Transition Animation

Android Shared Element Transition determines how shared element views are animated from one Activity/Fragment to another during a scene transition.

In pre-Lollipop devices Android used to support transitions between activities and fragments that involved transitions of the entire view hierarchies. However there are many cases when a view (let’s say ListView) consists of different row items. More often than not, clicking any row would show details of that respective row in the next screen. So to emphasise continuity between the two activities, we’ll show a circular reveal animation. This improves the user experience by drawing their focus towards the relationship between the new screen and the previous screen. A Shared Element Transition like this is more commonly seen in music playlist apps.

Note: This type of transition works only for android SDK>21.

Let’s begin the implementation of the app. In this tutorial we’ll implement custom ListView rows and show the desired transition for each of them.

Android Shared Element Transition Animation Project Structure

Android Shared Element Transition Animation project

This project consists of 2 activities and a CustomAdapter for the ListView.

Android Transition Animation – Shared Element Transition Code

To enable this transitions add the following snippet inside the AppTheme tag in styles.xml.


<item name="android:windowContentTransitions">true</item> 

For both the layouts with this transition we need to assign a android:transitionName attribute.

The activity_main.xml populates a ListView and the details_activity.xml is for the the details screen. Both are shown below.


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:transitionName="@string/transition"
    android:orientation="vertical">

   <ListView
       android:layout_width="wrap_content"
       android:id="@+id/list_view"
       android:layout_height="wrap_content"/>

</LinearLayout>

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="@dimen/activity_horizontal_margin"
    android:id="@+id/layout"
    android:transitionName="@string/transition"
    tools:context="com.journaldev.sharedelementtransition.MainActivity">

    <TextView
        android:gravity="center"
        android:textColor="@android:color/white"
        android:id="@+id/heading"
        android:layout_width="match_parent"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:layout_height="wrap_content" />


    <TextView
        android:gravity="center"
        android:id="@+id/language"
        android:textColor="@android:color/white"
        android:layout_width="match_parent"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_height="wrap_content"
        android:layout_below="@+id/heading"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />


    <TextView
        android:gravity="center"
        android:id="@+id/desc"
        android:textColor="@android:color/white"
        android:layout_width="match_parent"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
         />

</RelativeLayout>

As you can see a android:transitionName attribute is declared as a string in the root view of both the layouts.

We’ve created a custom ListView which populates its layout from a ArrayList of String arrays. The layout and adapter of the ListView are given below.


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:padding="@dimen/activity_horizontal_margin"
    android:background="@color/md_black_1000"
    android:layout_margin="5dp"
    android:id="@+id/rl"
    android:layout_height="wrap_content">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:id="@+id/primary_textview"
        android:gravity="center"
        android:textColor="@android:color/white"
         />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:id="@+id/textView"
        android:layout_below="@+id/primary_textview"
        android:textColor="@android:color/white"
        android:gravity="center"
         />

</RelativeLayout>

public class CustomAdapter extends BaseAdapter {
    ArrayList<String[]> arrayList;
    Context c;

    public CustomAdapter(Context c, ArrayList<String[]> list) {
        arrayList = list;
        this.c = c;

    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return arrayList.size();
    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return arrayList.get(position);
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        View row = null;
        LayoutInflater inflater = (LayoutInflater) c
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        if (convertView == null) {
            row = inflater.inflate(R.layout.row_layout, parent,
                    false);
        } else {
            row = convertView;
        }
        String[] detail = arrayList.get(position);


        RelativeLayout rl= (RelativeLayout)row.findViewById(R.id.rl);
        rl.setBackgroundColor(Color.parseColor(detail[3]));
        TextView name = (TextView) row.findViewById(R.id.primary_textview);
        name.setText(detail[0]);
        TextView email = (TextView) row.findViewById(R.id.textView);
        email.setText(detail[1]);

        return row;
    }

}

The MainActivity.java and DetailsActivity.java are given below.


package com.journaldev.sharedelementtransition;

import android.content.Intent;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

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


        final ArrayList<String[]> values = new ArrayList<String[]>();
        values.add(new String[]{"Android", "Java", getString(R.string.android),'#' + Integer.toHexString(getResources().getColor(R.color.md_light_green_900))});
        values.add(new String[]{"iOS", "Swift", getString(R.string.ios),'#' + Integer.toHexString(getResources().getColor(R.color.md_amber_A700))});
        values.add(new String[]{"Xamarin", "C#",getString(R.string.xamarin),'#' + Integer.toHexString(getResources().getColor(R.color.md_pink_A700))});
        values.add(new String[]{"PhoneGap", "HTML CSS and JScript",getString(R.string.phonegap),'#' + Integer.toHexString(getResources().getColor(R.color.md_brown_800))});


        ListView listView = (ListView) findViewById(R.id.list_view);
        CustomAdapter adapter = new CustomAdapter(this, values);
        listView.setAdapter(adapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                Intent intent = new Intent(MainActivity.this, DetailsActivity.class);
                intent.putExtra("array",values.get(position));
                // Get the transition name from the string
                String transitionName = getString(R.string.transition);

                ActivityOptionsCompat options =

                        ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this,
                                view,   // Starting view
                                transitionName    // The String
                        );

                ActivityCompat.startActivity(MainActivity.this, intent, options.toBundle());
            }
        });
    }
}

When an activity is finished, instead of finish() we invoke ActivityCompat.finishAfterTransition(this); as shown in the code below.


public class DetailsActivity extends AppCompatActivity {

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

       String[] array= getIntent().getStringArrayExtra("array");

        RelativeLayout rl= (RelativeLayout)findViewById(R.id.layout);
        rl.setBackgroundColor(Color.parseColor(array[3]));

        TextView textView= (TextView)findViewById(R.id.heading);
        textView.setText(array[0]);
        TextView type= (TextView)findViewById(R.id.language);
        type.setText(array[1]);
        TextView desc=(TextView)findViewById(R.id.desc);
        desc.setText(array[2]);

    }

    @Override
    public void onBackPressed() {
        ActivityCompat.finishAfterTransition(this);
    }
}

The output of the application in action is given below.
android transition animation, shared element transition android

This brings an end to this tutorial. You can download the final Android Transition Animation – Shared Element Transition Project from the link below.

Comments

  1. Dev says:

    It’s nice

  2. Ajay says:

    this is the best tutorial for >api 21

    1. Anupam says:

      Hi Ajay,
      Glad to hear that!

      Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages