In this tutorial we’ll implement a different kind of animation transition namely Shared Element Transition between activities.
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.
This project consists of 2 activities and a CustomAdapter for the ListView.
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="https://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="https://schemas.android.com/apk/res/android"
xmlns:tools="https://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="https://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),"https://www.journaldev.com/10473/#" + Integer.toHexString(getResources().getColor(R.color.md_light_green_900))});
values.add(new String[]{"iOS", "Swift", getString(R.string.ios),"https://www.journaldev.com/10473/#" + Integer.toHexString(getResources().getColor(R.color.md_amber_A700))});
values.add(new String[]{"Xamarin", "C#",getString(R.string.xamarin),"https://www.journaldev.com/10473/#" + Integer.toHexString(getResources().getColor(R.color.md_pink_A700))});
values.add(new String[]{"PhoneGap", "HTML CSS and JScript",getString(R.string.phonegap),"https://www.journaldev.com/10473/#" + 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.
This brings an end to this tutorial. You can download the final Android Transition Animation – Shared Element Transition Project from the link below.