Shared Element Transitions Android Example

In this tutorial, you can learn how to use shared element transitions between android activities. We can display animations when launch new activity.

In android api level 21, Shared Element Transition feature was introduced. So we need to check android version to use shared element transition in our app if we support android version below lollipop.

In this example, We create two activities. In first activity, we display country name. We display country details in second activity. So whenever user moves from first activity to second activity, he can see animation changes.

 

Add below line in your theme in your style.xml

First we need to enable window content transitions in our application to use shared element transitions.

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

Create First Activity

In this activity, we display countries names with images in list with the help of cardview.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_country"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:clipToPadding="false"
android:paddingBottom="15dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>
 

Country.kt

data class Country (val name: String, val image: Int, val desc: String) : Serializable
 

MainActivity.kt

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

val listCountries = ArrayList<Country>()

recycler_country.layoutManager = GridLayoutManager(this@MainActivity, 2)
var countriesAdapter = CountriesAdapter(this, listCountries)
recycler_country.adapter = countriesAdapter

}
}
 

country_row.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_country_row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="10dp"
android:layout_marginTop="15dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<ImageView
android:id="@+id/img_country_row"
android:layout_width="0dp"
android:layout_height="150dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:scaleType="centerCrop" />

<TextView
android:id="@+id/txt_country_row"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginBottom="12dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:textSize="22sp"
android:textStyle="bold"
android:textColor="@android:color/white"/>

</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.cardview.widget.CardView>
 

CountriesAdapter.kt

class CountriesAdapter (private val context: Context, private var listCountries: MutableList<Country>) : RecyclerView.Adapter<CountriesAdapter.MyViewHolder>() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val inflater = LayoutInflater.from(context)
val view: View = inflater.inflate(R.layout.country_row,parent,false)
return MyViewHolder(view)
}

override fun getItemCount(): Int {
return listCountries.size
}

override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val getCountry = listCountries[position]
holder.imageCountry?.setImageResource(getCountry.image)
holder.nameCountry?.text = getCountry.name

holder.cardCountry?.setOnClickListener {
val detailsIntent = Intent(context, DetailsActivity::class.java)
detailsIntent.putExtra("country",getCountry)
context.startActivity(detailsIntent)
}
}

class MyViewHolder(var view: View) : RecyclerView.ViewHolder(view){

var cardCountry: CardView? = null
var imageCountry: ImageView? = null
var nameCountry: TextView? = null

init {
cardCountry = view.findViewById(R.id.card_country_row)
imageCountry = view.findViewById(R.id.img_country_row)
nameCountry = view.findViewById(R.id.txt_country_row)
}

}

}
 
 

Create Second Activity

In this activity, we display country name, image and description.

activity_details.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">

<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar_details"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorPrimary">

<TextView
android:id="@+id/txt_title_details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="30sp"
android:textStyle="bold"
android:gravity="center"
android:textColor="@android:color/white" />

</androidx.appcompat.widget.Toolbar>

<ImageView
android:id="@+id/img_country_details"
android:layout_width="0dp"
android:layout_height="300dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar_details"
android:scaleType="fitXY" />

<TextView
android:id="@+id/txt_country_desc_details"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/img_country_details"
android:layout_margin="15dp"
android:textSize="18sp"/>

</androidx.constraintlayout.widget.ConstraintLayout>
 

DetailsActivity.kt

class DetailsActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_details)

setSupportActionBar(toolbar_details)
supportActionBar?.setDisplayShowTitleEnabled(false)

if(intent.hasExtra("country")){
val getCountry = intent.getSerializableExtra("country") as Country
img_country_details.setImageResource(getCountry.image)
txt_title_details.text = getCountry.name
txt_country_desc_details.text = getCountry.desc
}

}

}
 
 

Assign same transition name for both images

First we add image transition between activities. We add transition name in strings.xml file. So we can assign same name for both images.

strings.xml

<string name=”img_transition”>countryImage</string>
 

country_row.xml

In first activity, we displays countries in list. So we need to assign transition name to image in adapter row layout.

<ImageView
android:id=”@+id/img_country_row”
.
.
android:transitionName=”@string/img_transition”/>
 

activity_details.xml

<ImageView
android:id=”@+id/img_country_details”
.
.
android:transitionName=”@string/img_transition”/>
 
 

Add shared element transitions in intent

Now we add single image transition in intent which is used to launch second activity. For this ActivityOptionsCompat class is used.

val detailsIntent = Intent(context, DetailsActivity::class.java)
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(context as Activity, holder.imageCountry as ImageView, context.resources.getString(R.string.img_transition))
ActivityCompat.startActivity(context,detailsIntent,options.toBundle())
 
 

Multiple Shared Element Transitions

Now we want to add country name transition between activities. For this first we need to add transition name in both textviews same as we done for imageviews.

But the problem is we cant add multiple transitions direct in makeSceneTransitionAnimation method. So we need to use pair class which provides parameters for view and transition name. So we create two pairs for image and text transitions.

val detailsIntent = Intent(context, DetailsActivity::class.java)

val pair1: androidx.core.util.Pair<View,String> = androidx.core.util.Pair(holder.imageCountry as View,context.resources.getString(R.string.img_transition))
val pair2: androidx.core.util.Pair<View,String> = Pair(holder.nameCountry as View,context.resources.getString(R.string.title_transition))

val options = ActivityOptionsCompat.makeSceneTransitionAnimation(context as Activity, holder.imageCountry as ImageView, context.resources.getString(R.string.img_transition))
ActivityCompat.startActivity(context,detailsIntent,options.toBundle())

 
 
 
shared element transitions
 
 
 

Leave a Reply