androidandroid-animationandroid-cardviewandroid-transitionsshared-element-transition

Shared Element Transition on CardView with radius


I've been working on this problem for weeks and I'm still unable to solve this problem.

So, I have a CardView that contains a LinearLayout with an ImageView.

without radius

Without that radius Shared Element Transition works seamlessly. However, when I add radius (app:cardCornerRadius="25dp") to that CardView, the Shared Element Transition looks ugly because it remove the radius first and then start the animation.

with radius transition

1st Approach: ObjectAnimator

I create ObjectAnimator to animate the radius value on card, and after the animation end it start the transition.

ObjectAnimator animator = ObjectAnimator
            .ofFloat(view, "radius", AppUtil.dpAsPixel(this, 25), 0);
animator.setDuration(150);
animator.addListener( // start new Activity with Transition );
animator.start();

This works but it doesn't looks great, because the transition wait the animation to finish before starting the transition. What I need is the radius is animating while doing transition to new Activity (something like ORDERING_TOGETHER in TransitionSet).

2nd Approach - ChangeImageTransform

I've read a StackOverflow post to use Transformation Class like ChangeImageTransform and ChangeBounds.

I did define my application theme like it was suggested (my_transition contains ChangeImageTransform transitionSet)

<item name="android:windowSharedElementEnterTransition">@transition/my_transition</item>
<item name="android:windowSharedElementExitTransition">@transition/my_transition</item>

But it doesn't work..

3rd Approach - Naive

My last attempt is to force the target ImageView to have a radius of 25dp too. Because maybe my CardView is transformed into square because the target ImageView is square, but as you can guess, it doesn't work.

4th Approach - Not Using CardView

As you can see, I'm using Penguin images and use CardView to make a radius. I can make the image rounded by using Image Transformation, but I still don't think that's the right way to create a Shared Element Transition..

And here is my question, is there a way to make a Shared Element Transition with CardView radius works without removing the radius first?


Solution

  • I finally able to solve it. For those who are interested, here's how:

    Why it remove radius before starting transition? Because the target ImageView doesn't have any radius.

    activity_detail.xml

    <ImageView
        android:id="@+id/iv_image_cover"
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:scaleType="centerCrop"
        android:src="@{animal.imageRes}"
        android:transitionName="animalImage"
        tools:src="@drawable/acat"
    />
    

    When I use CardView without radius, it's not noticable, but it's actually turned into target Shared View.

    1. To achieve radius to no-radius transition you have to set the target Shared View to be rounded. I'm simply wrap it using a Card View (with radius).

    activity_detail.xml

    <android.support.v7.widget.CardView
        android:id="@+id/card"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:transitionName="card"
        app:cardCornerRadius="25dp"
    >
    
        <ImageView
            android:id="@+id/iv_image_cover"
            android:layout_width="match_parent"
            android:layout_height="250dp"
            android:scaleType="centerCrop"
            android:src="@{animal.imageRes}"
            android:transitionName="animalImage"
            tools:src="@drawable/acat"
        />
    
    </android.support.v7.widget.CardView>
    
    1. Be sure to change your makeSceneTransition to use "card" instead of "animalImage"

    ListActivity.class

    ActivityOptionsCompat option = ActivityOptionsCompat
    .makeSceneTransitionAnimation(ListActivity.this, cardView, "card");
    
    startActivity(intent, option.toBundle());
    
    1. In the DetailActivity, you can start a radius animation when the transition start.

    DetailActivity.java

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().getSharedElementEnterTransition()
            .addListener(new Transition.TransitionListener() {
                @Override
                public void onTransitionStart(Transition transition) {
                    ObjectAnimator animator = ObjectAnimator
                        .ofFloat(activityDetailBinding.card, "radius", 0);
                    animator.setDuration(250);
                    animator.start();
                }
            });
    }
    
    1. Enjoy the smooth transition

    final animation

    Note: gist for layout and activities