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.
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
country_row.xml
In first activity, we displays countries in list. So we need to assign transition name to image in adapter row layout.
android:id=”@+id/img_country_row”
.
.
android:transitionName=”@string/img_transition”/>
activity_details.xml
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 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 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())

