This is a short blog describing how to create shared element transitions mostly following the MVP pattern with routers and interactors. As it might not be an amateur way of doing so, I would love to receive feedback and improvements on the way it should or rather can be done better.

shared_element_animation

Now, that’s an example of a shared element transition, where in the element you tap on shares an animation with the activity or fragment that loads the details (as per this example).

There are many references available online to understand other forms of shared transition animations and ways of how to combine them with different views.

In our example, we are simply considering one element and an animation happening when opening two activities, Activity A displays the list, Activity B displays the details.

The most ideal way would be to start an activity from the view itself, but since that is not what i was wanting to do, i used the approach below:

  1. Define transitionName attribute in the xml of both the activities (one on the image where you perform the click, the second one on the  layout that would be loaded (the detail xml)
    ActivityA's xml
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.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="wrap_content"
        android:background="@color/colorWhite"
        android:padding="@dimen/padding_tiny"
        android:transitionName="@string/transition_name"
        tools:context="com.movieapp.movie.home.view.MainActivity">
    
        // all other elements here
    </android.support.constraint.ConstraintLayout>
    ActivityB's xml
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 
        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"
        android:background="@color/colorGray"
        android:orientation="vertical"
        android:transitionName="@string/transition_name">
    
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            style="@style/MovieApp.ActionBar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize" />
    
        // all other ui elements here
    </LinearLayout>
  2. Identify the click on the image or itemView in the adapter class
  3. Pass the view to the presenter via a callback or listener interface
    listener.onMoreInfoClicked(itemView, modelAdapter.getMovieId(adapterPosition));
  4. The ActivityCompatOptions object instance is required for shared element transitions, so we create one using the view received by the presenter making a call to the view
    ActivityOptionsCompat options = mainView.getActivityOptions(view);
    router.openDetails(movieId, options);
  5. Receive the activityOptions instance and pass it to the router (We would return the following below from the view)
    return ActivityOptionsCompat.
                   makeSceneTransitionAnimation(activity, view,
                            view.getContext().getString(R.string.transition_name));
  6. Start a new activity from the router passing the options and any other extra params you wish to send.
    ActivityB.startActivity(activity, movieId, options);

    The startActivity method will look as under:

    public static void startActivity(@NonNull final AppCompatActivity activity,
                                     final long movieId,
                                     final ActivityOptionsCompat options) {
        final Intent intent = new Intent(activity, ActivityB.class);
        final Bundle bundle = new Bundle();
        bundle.putLong(ConstantIntentExtra.EXTRA_MOVIE_ID, movieId);
        intent.putExtra(ConstantIntentExtra.EXTRA_BUNDLE_MOVIE, bundle);
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            activity.startActivity(intent, options.toBundle());
        } else {
            activity.startActivity(intent);
        }
    }

    Things to consider:

  7. startActivity overload with 2 params, is only available since API Level 16, while transitionName attribute is only available since API Level 21.
  8. A styles file needs to be created for values-v21 to support the animations, the following line has to be added to the app style
    <item name="android:windowContentTransitions">true</item>
  9. In order for the same transition effect to be visible when returning from ActivityB, we add the following to ActivityB’s router file:
    activity.supportFinishAfterTransition();

    Not adding this, and simply calling activity.finish() will result in an abrupt exit of the screen.

This solution may not be optimal, and i look for feedback as to how it can be improved to suit MVP pattern most precisely with Routers and Interactors.

References:

  1. http://blogs.quovantis.com/how-to-apply-shared-element-transitions-in-android/
  2. http://myhexaville.com/2016/12/23/android-advanced-circular-reveal/
  3. https://android.jlelse.eu/a-little-thing-that-matter-how-to-reveal-an-activity-with-circular-revelation-d94f9bfcae28
  4. http://mikescamell.com/shared-element-transitions-part-4-recyclerview/

Have fun!

 

Advertisements