Adv

Android Shared Element Transition

According to android documentation,  shared elements transition determine how views that are shared between two activities transition between these activities. For example, if two activities have the same image in different positions and sizes, the changeImageTransform shared element transition translates and scales the image smoothly between these activities.

This thread looks at examples and libraries relating to Shared Transitions in android. Feel free to contribute more examples, links and libraries.

Share
Adv

3 Examples

  1. Easily Implement Shared Transition on Images

    You can easily implement shared element transition on images using this library known as Transitional ImageView.

    Let’s show you how to.

    Step 1 – Install the Library

    First register jitpack as a repository in your app level build.gradle:

    allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }

    Then install the library:

    implementation 'com.github.mostafaaryan:transitional-imageview:v0.2.2'
    }

    Step 2

    Create Transitional ImageView in your layout by pasting the following code:

    <com.mostafaaryan.transitionalimageview.TransitionalImageView
            android:id="@+id/transitional_image"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:scaleType="fitXY"
            android:adjustViewBounds="true"
            app:res_id="@drawable/sample_image" />

    Step 3

    Now build a TransitionImageObject and set it to the TransitionalImageView:

    TransitionalImageView transitionalImageView = (TransitionalImageView) findViewById(R.id.transitional_image);
    TransitionalImage transitionalImage = new TransitionalImage.Builder()
                                        .duration(500)
                                        .backgroundColor(ContextCompat.getColor(MainActivity.this, R.color.color))
                                        .image(R.drawable.sample_image)
                                        /* or */
                                        .image(bitmap)
                                        .create();
    transitionalImageView.setTransitionalImage(transitionalImage);

    Full Example

    Here is a beautiful example for using this library.

    (a). Shoe.java

    The model class to define a single shoe.

    public class Shoe {
    
        private String Title;
        private String imageUrl;
    
        public Shoe(String title, String imageUrl) {
            Title = title;
            this.imageUrl = imageUrl;
        }
    
        public String getTitle() {
            return Title;
        }
    
        public String getImageUrl() {
            return imageUrl;
        }
    
    }

     

    (b). ShoeAdapter.java

    Then the recyclerview adapter.

    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.os.AsyncTask;
    import android.support.v4.content.ContextCompat;
    import android.support.v7.widget.RecyclerView;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    import com.ariannejad.mostafa.transitional_imageview_implementation.R;
    import com.ariannejad.mostafa.transitional_imageview_implementation.controller.MainActivity;
    import com.ariannejad.mostafa.transitional_imageview_implementation.model.Shoe;
    import com.mostafaaryan.transitionalimageview.TransitionalImageView;
    import com.mostafaaryan.transitionalimageview.model.TransitionalImage;
    import com.squareup.picasso.Picasso;
    
    
    import java.io.IOException;
    import java.util.ArrayList;
    
    /**
     * Created by Mostafa Aryan Nejad on 8/11/17.
     */
    
    public class ShoeAdapter extends RecyclerView.Adapter<ShoeAdapter.ViewHolder> {
    
        Context mContext;
        ArrayList<Shoe> shoes = new ArrayList<>();
    
        public ShoeAdapter(Context context, ArrayList<Shoe> shoes) {
            mContext = context;
            this.shoes = shoes;
        }
    
    
        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.item_shoe, parent, false);
    
            return new ViewHolder(view);
        }
    
        @Override
        public void onBindViewHolder(final ViewHolder holder, final int position) {
    
            final Shoe shoe = shoes.get(position);
    
            AsyncTask.execute(new Runnable() {
                @Override
                public void run() {
                    try{
    
                        final Bitmap bitmap = Picasso.with(mContext).load(shoe.getImageUrl()).get();
                        ((Activity) mContext).runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                TransitionalImage transitionalImage = new TransitionalImage.Builder()
                                        .duration(500)
                                /*.backgroundColor(ContextCompat.getColor(, R.color.colorAccent))*/
                                        /*.image(R.drawable.sample_image)*/
                                        .image(bitmap)
                                        .create();
                                holder.image.setTransitionalImage(transitionalImage);
                                bitmap.recycle();
                            }
                        });
                    } catch (IOException e){e.printStackTrace();}
                }
            });
    
    
            holder.title.setText(shoe.getTitle());
            holder.sizes.setText("37,38,39,40");
    
    
        }
    
        @Override
        public int getItemCount() {
            return shoes.size();
        }
    
        public static class ViewHolder extends RecyclerView.ViewHolder {
    
            public TextView title;
            public TextView sizes;
            public TransitionalImageView image;
    
    
            public ViewHolder(View itemView) {
                super(itemView);
    
                title = (TextView) itemView.findViewById(R.id.shoe_title);
                sizes = (TextView) itemView.findViewById(R.id.shoe_sizes);
                image = (TransitionalImageView) itemView.findViewById(R.id.shoe_image);
    
            }
    
        }
    
    
    }

     

    (c). ShoeListActivity.java

    The shoe list activity:

    import android.support.design.widget.AppBarLayout;
    import android.support.design.widget.CollapsingToolbarLayout;
    import android.support.design.widget.TabLayout;
    import android.support.v7.app.ActionBar;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.support.v7.widget.Toolbar;
    
    import com.ariannejad.mostafa.transitional_imageview_implementation.R;
    import com.ariannejad.mostafa.transitional_imageview_implementation.adapter.ShoeAdapter;
    import com.ariannejad.mostafa.transitional_imageview_implementation.model.Shoe;
    
    import java.util.ArrayList;
    
    public class ShoeListActivity extends AppCompatActivity {
    
        private RecyclerView shoeRecyclerView;
        private ArrayList<Shoe> shoes = new ArrayList<>();
        private ActionBar actionBar;
        private AppBarLayout appBarLayout;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_shoe_list);
    
            shoeRecyclerView = (RecyclerView) findViewById(R.id.shoe_recycler_view);
            CollapsingToolbarLayout collapsingToolbar =
                    (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
            appBarLayout = (AppBarLayout) findViewById(R.id.app_bar_layout);
            setOnOffsetChangedListener();
            collapsingToolbar.setTitleEnabled(false);
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
            actionBar = getSupportActionBar();
            if(actionBar != null) actionBar.setTitle("");
    
    
            populateList();
    
        }
    
        private void populateList() {
            shoes.add(new Shoe("Skechers Relaxed Fit Empire Game On Walking Shoe",
                    "https://www.shoes.com/pm/skech/skech800828_42965_hd2.jpg"));
    
            shoes.add(new Shoe("Skechers After Burn Memory Fit Geardo High Top Trainer",
                    "https://www.shoes.com//pm/skech/skech798492_42965_hd2.jpg"));
    
            shoes.add(new Shoe("New Balance Fresh Foam Zante v3 Running Shoe",
                    "https://www.shoes.com/pi/newba/hd/newba805216_436896_hd.jpg"));
    
            for(int i = 0 ; i <= 5 ; i++ ) {
                shoes.addAll(shoes);
            }
    
            displayList();
        }
    
        private void displayList() {
            RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
            RecyclerView.Adapter adapter = new ShoeAdapter(this, shoes);
            shoeRecyclerView.setLayoutManager(layoutManager);
            shoeRecyclerView.setAdapter(adapter);
        }
    
        private void setOnOffsetChangedListener() {
    
            appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
    
                boolean isDisplayed = false;
    
                @Override
                public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                    int totalScroll = appBarLayout.getTotalScrollRange();
    
                    if (totalScroll + verticalOffset == 0) {
                        if (actionBar != null) {
                            actionBar.setTitle("Sneakers");
                        }
                        isDisplayed = true;
                    } else if (isDisplayed) {
                        if (actionBar != null)
                            actionBar.setTitle("");
                        isDisplayed = false;
                    }
                }
    
            });
    
        }
    
    
    }

     

    (d). MainActivity.java

    And finally the main activity.

    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.os.AsyncTask;
    import android.support.v4.content.ContextCompat;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    
    import com.ariannejad.mostafa.transitional_imageview_implementation.R;
    import com.mostafaaryan.transitionalimageview.TransitionalImageView;
    import com.mostafaaryan.transitionalimageview.model.TransitionalImage;
    import com.squareup.picasso.Picasso;
    
    import java.io.IOException;
    
    
    public class MainActivity extends AppCompatActivity {
    
        private String imageUrl = "https://image.freepik.com/free-icon/android-logo_318-54237.jpg";
        TransitionalImageView tiv;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            tiv = (TransitionalImageView) findViewById(R.id.sample_image);
    
            loadImage();
    
        }
    
        private void loadImage() {
    
            /*
            ImageLoader imageLoader;
            imageLoader = ImageLoader.getInstance();
            imageLoader.init(ImageLoaderConfiguration.createDefault(this));
            AsyncTask.execute(new Runnable() {
                @Override
                public void run() {
                    DisplayImageOptions dio = new DisplayImageOptions.Builder()
                            .cacheInMemory(false).build();
                    final Bitmap bmp = imageLoader.loadImageSync(imageUrl, dio);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            tiv.setImage(bmp);
                        }
                    });
                }
            });*/
    
    
            /* Glide.with(this).asBitmap().load(imageUrl).into(new SimpleTarget<Bitmap>() {
                @Override
                public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
                    tiv.setImage(resource);
                }
            }); */
    
            AsyncTask.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        final Bitmap b = Picasso.with(MainActivity.this).load(imageUrl).get();
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
    //                            tiv.setImage(b);
                                TransitionalImage transitionalImage = new TransitionalImage.Builder()
                                        .duration(500)
                                        .backgroundColor(ContextCompat.getColor(MainActivity.this, R.color.colorAccent))
                                        //.image(R.drawable.sample_image)
                                        .image(b)
                                        .create();
                                tiv.setTransitionalImage(transitionalImage);
                            }
                        });
    
                    } catch (IOException e) {e.printStackTrace();}
                }
            });
    
    
        }
    
    
        public void onClickShoes(View view) {
            startActivity(new Intent(this, ShoeListActivity.class));
        }
    
    
    
    }

     

    Demo

    Here is the demo of what you get when you run the project.

    Android Shared Element Image Transition Example

    Download

    Here are the download links.

    1. Direct Download here.
    2. Follow Author here.
  2. Adv
  3. Kotlin Shared Transition RecyclerView and Fragments

    This is also a simple shared transitions example written in Kotlin. This time round however a recyclerview is the shared element among two fragments.

    Tools

    Here are the things to keep in mind:

    • Programming Language – Kotlin
    • Minimum SDK – 21

    1. Create Transitions

    In  a folder known as transitions under resources add the following:

    (a). change_bounds.xml

    <?xml version="1.0" encoding="utf-8"?>
    <transitionSet>
        <changeBounds />
    </transitionSet>

     

    (b). change_image_transform.xml

    Then:

    <?xml version="1.0" encoding="utf-8"?>
    <transitionSet>
        <changeImageTransform />
    </transitionSet>

     

    2. Design Layouts

    You will find the layouts in the code.

    3. Write Code

    Code is written in Kotlin in this case.

    (a). Fragment1.kt

    Here is the code for the first fragment.

    import android.os.Bundle
    import android.view.LayoutInflater
    import android.view.View
    import android.view.ViewGroup
    import androidx.fragment.app.Fragment
    import androidx.recyclerview.widget.LinearLayoutManager
    import kotlinx.android.synthetic.main.activity_main.*
    import android.transition.ChangeBounds
    import android.transition.ChangeImageTransform
    
    
    class Fragment1: Fragment() {
    
        private lateinit var lm: LinearLayoutManager
    
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            return inflater.inflate(R.layout.activity_main, container, false)
        }
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            lm = LinearLayoutManager(context, LinearLayoutManager.VERTICAL,
                false)
            rv.layoutManager = lm
            val adapter = MainActivity.Adapter()
            rv.adapter = adapter
            btn.setOnClickListener {
    
    //            val changeImageTransform =
    //                TransitionInflater.from(context).inflateTransition(R.transition.change_image_transform)
    //            val changeBoundsTransform =
    //                TransitionInflater.from(context).inflateTransition(R.transition.change_bounds)
    
                sharedElementReturnTransition = ChangeBounds()
                sharedElementEnterTransition = ChangeImageTransform()
                exitTransition = ChangeBounds()
    
                val fragment2 = Fragment2()
                // Setup transition on second fragment
                fragment2.sharedElementEnterTransition = ChangeBounds()
                fragment2.enterTransition = ChangeBounds();
    
                val firstVisiblePosition = lm.findFirstVisibleItemPosition()
                val lastVisiblePosition = lm.findLastVisibleItemPosition()
                val transaction = fragmentManager!!.beginTransaction()
                    .replace(R.id.container, fragment2, fragment2::class.java.simpleName)
                    .addToBackStack("name")
                for (i in firstVisiblePosition..lastVisiblePosition) {
                    val holderForAdapterPosition =
                        rv.findViewHolderForAdapterPosition(i) as MainActivity.Adapter.Holder
                    val itemView = holderForAdapterPosition.itemView
                    transaction.addSharedElement(itemView, "unique_key_$i")
                }
                transaction.commit()
            }
        }
    }

     

    (b). Fragment2.kt

    Add the following code in second fragment.

    import android.os.Bundle
    import android.view.LayoutInflater
    import android.view.View
    import android.view.ViewGroup
    import androidx.fragment.app.Fragment
    import androidx.recyclerview.widget.LinearLayoutManager
    import kotlinx.android.synthetic.main.activity_main.*
    
    class Fragment2: Fragment() {
    
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            return inflater.inflate(R.layout.activity_main, container, false)
        }
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            val lm = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL,
                false)
            rv.layoutManager = lm
            val adapter = MainActivity.Adapter()
            rv.adapter = adapter
            btn.setOnClickListener {
            }
            postponeEnterTransition()
        }
    
        override fun onStart() {
            super.onStart()
            rv.post {
                startPostponedEnterTransition()
            }
        }
    }

     

    (c). ScndActivity.kt

    Then the second activity.

    import android.os.Bundle
    import android.os.PersistableBundle
    import androidx.appcompat.app.AppCompatActivity
    import androidx.recyclerview.widget.LinearLayoutManager
    import kotlinx.android.synthetic.main.activity_main.*
    
    class ScndActivity: AppCompatActivity() {
    
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            val lm = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL,
                false)
            rv.layoutManager = lm
            val adapter = MainActivity.Adapter()
            rv.adapter = adapter
            btn.setOnClickListener {
    
                //            val currentOrientation = lm.orientation
    //            if (currentOrientation == LinearLayoutManager.VERTICAL) {
    //                lm.orientation = LinearLayoutManager.HORIZONTAL
    //            } else {
    //                lm.orientation = LinearLayoutManager.VERTICAL
    //            }
    //            adapter.notifyItemRangeChanged(1, adapter?.itemCount ?: 0)
            }
            supportPostponeEnterTransition()
            rv.post {
                supportStartPostponedEnterTransition()
            }
        }
    }

     

    (d). MainActivity.kt

    And lastly the main activity,

    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import android.view.LayoutInflater
    import android.view.View
    import android.view.ViewGroup
    import androidx.recyclerview.widget.LinearLayoutManager
    import androidx.recyclerview.widget.RecyclerView
    
    
    class MainActivity : AppCompatActivity() {
    
        private lateinit var lm: LinearLayoutManager
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.cont)
            val fragment1 = Fragment1()
            supportFragmentManager.beginTransaction()
                .add(R.id.container, fragment1, Fragment1::class.java.simpleName)
                .commit()
    //        lm = LinearLayoutManager(this, LinearLayoutManager.VERTICAL,
    //            false)
    //        rv.layoutManager = lm
    //        val adapter = Adapter()
    //        rv.adapter = adapter
    //        btn.setOnClickListener {
    //            val firstVisiblePosition = lm.findFirstVisibleItemPosition()
    //            val lastVisiblePosition = lm.findLastVisibleItemPosition()
    //            val pairs = ArrayList<Pair<View, String>>()
    //            for (i in firstVisiblePosition..lastVisiblePosition) {
    //                val holderForAdapterPosition =
    //                    rv.findViewHolderForAdapterPosition(i) as Adapter.Holder
    //                val itemView = holderForAdapterPosition.itemView
    //                pairs.add(Pair(itemView, "unique_key_$i"))
    //            }
    //            val bundle = ActivityOptions.makeSceneTransitionAnimation(
    //                this,
    //                *pairs.toTypedArray()
    //            ).toBundle()
    //            val fragment1 = Fragment1()
    //            supportFragmentManager.beginTransaction()
    //                .add(fragment1, Fragment1::class.java.simpleName)
    //                .commit()
    //            startActivity(Intent(this, ScndActivity::class.java), bundle)
    //        }
        }
    
        override fun onResume() {
            super.onResume()
        }
    
        class Adapter : RecyclerView.Adapter<Adapter.Holder>() {
    
            override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder =
                Holder(
                    LayoutInflater.from(parent.context).inflate(
                        R.layout.item_item,
                        parent,
                        false
                    )
                )
    
            override fun getItemCount(): Int = 10
    
            override fun onBindViewHolder(holder: Holder, position: Int) {
                holder.bind(position)
            }
    
            class Holder(view: View) : RecyclerView.ViewHolder(view) {
    
                fun bind(position: Int) {
                    itemView.transitionName = "unique_key_$position"
                }
            }
        }
    }

     

    Demo

    Here is what you get when you run the project.

    Android Kotlin Shared Transition Example RecyclerView

    Download

    1. Direct Download here.
    2. Follow Author here.
  4. Adv
  5. Java Shared Transition with Fragments and FloatingActionButton

    This is a simple one-class example to utilize a shared element transition within fragments in an android activity. The programming language is Java. While it is not written in androidx, you can easily update it to androidx fragments and it doesn’t utilize any third partt library.

    shared

    Transitions

    These are written in XML.  Tyically you create a transition resource directory and place the XML.

    (a). shared_enter_transition.xml

    Here is the code:

    <?xml version="1.0" encoding="utf-8"?>
    <transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="@integer/default_anim_duration">
    
        <changeTransform/>
        <arcMotion
            android:minimumHorizontalAngle="0"
            android:minimumVerticalAngle="15"
            android:maximumAngle="90" />
        <changeBounds />
    
    </transitionSet>

     

    Activities

    Here are the activities

    (a). MainActivity.java

    Here is the main activity:

    import android.animation.Animator;
    import android.app.Fragment;
    import android.os.Bundle;
    import android.support.v4.view.ViewCompat;
    import android.support.v7.app.ActionBarActivity;
    import android.transition.Fade;
    import android.transition.Transition;
    import android.transition.TransitionInflater;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewAnimationUtils;
    import android.view.ViewGroup;
    import android.view.animation.AccelerateInterpolator;
    
    public class FabActivity extends ActionBarActivity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_fab);
    
            getFragmentManager()
                    .beginTransaction()
                    .add(R.id.frag_content, TitleFragment.newInstance())
                    .commit();
        }
    
    
        public static class TitleFragment extends Fragment {
            public static TitleFragment newInstance() {
                return new TitleFragment();
            }
    
            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                final View view = inflater.inflate(R.layout.fragment_fab_title, container, false);
                final View fabbutton = view.findViewById(R.id.fab);
                fabbutton.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        final ControlsFragment controlsFragment = ControlsFragment.newInstance();
    
                        setupSharedElementTransition(controlsFragment);
                        Fade f = new Fade();
                        f.setStartDelay(250);
                        setExitTransition(f);
    
                        getFragmentManager()
                                .beginTransaction()
                                .replace(R.id.frag_content, controlsFragment)
                                .addToBackStack("controls")
                                .addSharedElement(fabbutton, "pause_button")
                                .commit();
                    }
                });
                return view;
            }
    
            private void setupSharedElementTransition(final ControlsFragment controlsFragment) {
                Transition sharedTransition = TransitionInflater.from(getActivity()).inflateTransition(R.transition.shared_enter_transition);
                controlsFragment.setSharedElementEnterTransition(sharedTransition);
                controlsFragment.setSharedElementReturnTransition(sharedTransition);
                sharedTransition.addListener(new Transition.TransitionListener() {
                    @Override
                    public void onTransitionEnd(Transition transition) {
                        controlsFragment.revealContent();
                    }
    
                    @Override
                    public void onTransitionStart(Transition transition) {
                    }
    
                    @Override
                    public void onTransitionCancel(Transition transition) {
                    }
    
                    @Override
                    public void onTransitionPause(Transition transition) {
                    }
    
                    @Override
                    public void onTransitionResume(Transition transition) {
                    }
                });
    
            }
    
    
        }
    
        public static class ControlsFragment extends Fragment {
    
            public static ControlsFragment newInstance() {
                return new ControlsFragment();
            }
    
    
            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                return inflater.inflate(R.layout.fragment_fab_controls, container, false);
            }
    
    
            public void revealContent() {
                View layout = getView().findViewById(R.id.controls_layout);
                animateRevealColor(layout);
            }
    
            private void animateRevealColor(View targetView) {
                int cx = (targetView.getLeft() + targetView.getRight()) / 2;
                int cy = (targetView.getTop() + targetView.getBottom()) / 2;
    
                cx += targetView.getTranslationX();
                cy += targetView.getTranslationY();
                int finalRadius = Math.max(targetView.getWidth(), targetView.getHeight());
    
                Animator anim = ViewAnimationUtils.createCircularReveal(targetView, cx, cy, 0, finalRadius);
                targetView.setBackgroundColor(getResources().getColor(R.color.accent_material_light));
                anim.setDuration(getResources().getInteger(R.integer.default_anim_duration));
                anim.setInterpolator(new AccelerateInterpolator());
                anim.addListener(new Animator.AnimatorListener() {
                    @Override
                    public void onAnimationEnd(Animator animator) {
                        animateScaleButton(getView().findViewById(R.id.ff_button));
                        animateScaleButton(getView().findViewById(R.id.rew_button));
                    }
    
                    @Override
                    public void onAnimationStart(Animator animator) {
                    }
    
                    @Override
                    public void onAnimationCancel(Animator animator) {
                    }
    
                    @Override
                    public void onAnimationRepeat(Animator animator) {
                    }
                });
                anim.start();
            }
    
            private void animateScaleButton(View view) {
                ViewCompat.animate(view)
                        .scaleX(1)
                        .scaleY(1)
                        .setDuration(250)
                        .start();
            }
        }
    
    }

    Demo

    Here is the demo of what you get when you run the project.

    Fragments Shared Element Transition

    Download Links

    1. Directly download the code here. (Please update it to androidx and reshare your code)
    2. Follow Author here.



Share an Example

Share an Example

Browse
What is the capital of Egypt? ( Cairo )