SharedElementTransition not animating image scale properly with Glide

Viewed 462

I am doing a shared element transition from a fragment with a RecyclerView to a detail view, where an image is shared between the two. The transition is mostly fine, but because the two images are different sizes, when I click on one, it scales the image to the final size, and then animates the ImageView bounds as it should. This results in the image not matching the size of the bounds during the animation.

Here is a video of what I'm describing

DetailFragment:

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        sharedElementEnterTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.move)
        ViewCompat.setTransitionName(binding.podcastImage, "podcastImage_${args.podcastId}")

        postponeEnterTransition()
    }

// called from onStart
private fun observeViewModel() {
        viewModel.podcastObservable.observe(this, Observer { podcast ->
            Glide.with(requireContext())
                .load(podcast.image)
                .into(binding.podcastImage)

            // other stuff

            startPostponedEnterTransition()
        })
    }

GridFragment:

fun navigateToPodcastDetailFragment(podcastId: String) {
        val args = Bundle()
        args.putString("podcast_id", podcastId)

        val directions = TopPodcastsFragmentDirections.viewPodcastDetails(podcastId)
        val extras = FragmentNavigatorExtras(
            podcast_image to "podcastImage_$podcastId"
        )

        Navigation.findNavController(requireActivity(), R.id.nav_host_fragment)
            .navigate(directions, extras)
    }

GridAdapter:

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        getItem(position).let { podcast ->
            with(holder) {
                Glide.with(holder.itemView.context)
                    .load(podcastList[position].image)
                    .dontAnimate()
                    .dontTransform()
                    .into(binding.thumbnail)
                bind(createOnClickListener(binding, podcast.id), podcast)
            }
        }
    }

ViewHolder.bind() {
    // other stuff
    ViewCompat.setTransitionName(binding.thumbnail, "podcast${value.id}")
} 

Grid item ImageView:

<ImageView
            android:id="@+id/thumbnail"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:transitionName="@string/podcastImageTransition"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:src="@drawable/ic_launcher_background" />

DetailFragment ImageView:

<ImageView
            android:id="@+id/podcast_image"
            android:layout_width="164dp"
            android:layout_height="164dp"
            android:scaleType="centerCrop"
            android:layout_marginTop="24dp"
            android:transitionName="@string/podcastImageTransition"
            app:layout_constraintTop_toBottomOf="@id/toolbar"
            app:layout_constraintStart_toStartOf="parent"
            tools:src="@drawable/ic_launcher_background"/>

I think I have the transition part mostly correct, but something about the way the image is being cropped or scaled isn't right during the transition.

Thanks in advance.

1 Answers

Make sure in DetailFragment to include .dontTransform() within Glide

// called from onStart
private fun observeViewModel() {
        viewModel.podcastObservable.observe(this, Observer { podcast ->
            Glide.with(requireContext())
                .load(podcast.image)
                .dontTransform()
                .into(binding.podcastImage)

            // other stuff

            startPostponedEnterTransition()
        })
    }

Also, I've been working on this all day (for an app I'm making coincidentally), and I just found something else you can try. Try removing the image scale type in the xml files.

Related