Reputation: 153
I want to transition between fragments with two shared elements. But the problem is: only one gets animated.
The shared elements are taken from a viewHolder from list in the first fragment. The transitions I use are from Material library, exactly these ones https://medium.com/androiddevelopers/material-motion-with-mdc-c1f09bb90bf9
Fragment A:
fragmentManager.commit {
replace([...])
setReorderingAllowed(true)
addSharedElement(viewA, viewA.transitionName)
addSharedElement(viewB, viewB.transitionName)
addToBackStack(fragmentClass.qualifiedName)
}
Fragment B:
sharedElementReturnTransition = MaterialContainerTransform().apply {
scrimColor = Color.TRANSPARENT
duration = 3000L
interpolator = DecelerateInterpolator()
}
binding.headerContainer.header.cover.transitionName = arguments?.getString("firstTrName") ?: return
binding.headerContainer.title.cover.transitionName = arguments?.getString("secondTrName") ?: return
binding.headerContainer.header.setImageResource(arguments?.getString("image") ?: return)
binding.headerContainer.title.text = arguments?.getString("title") ?: return
It seems like only the last element that I added in the commit{} is the one that transitions. I have checked everything, transition names are unique, all data is there in the second fragment, all transition names, it's not an argument problem. Any ideas? Help would be highly appreciated, this is a very important client request.
Upvotes: 1
Views: 1472
Reputation: 31
https://material.io/develop/android/theming/motion
Unlike traditional Android shared elements, it is not designed around a singular piece of shared content, such as an image, to be moved between two scenes. Instead, the shared element here refers to the bounding container of a start View or ViewGroup (e.g. the entire row layout of an item in a list) transforming its size and shape into that of an end View or ViewGroup (e.g. the root ViewGroup of a full screen Fragment). These start and end container Views are the “shared element” of a container transform. While these containers are being transformed, their contents are swapped to create the transition.
Two shared element doesn't work properly. When selecting start view from the top of the list, imageView becomes a container. When selecting from the bottom, textView becomes a container. (See difference between example1 and example5 from the gif below)
You can use traditional shared element transition instead of Material Motion.
EXAMPLE AND GIF
fragmentEnd.sharedElementEnterTransition = MaterialContainerTransform().apply {
scrimColor = Color.TRANSPARENT
containerColor = Color.TRANSPARENT
duration = 1000L
interpolator = DecelerateInterpolator()
}
fragmentEnd.sharedElementReturnTransition = MaterialContainerTransform().apply {
scrimColor = Color.TRANSPARENT
containerColor = Color.TRANSPARENT
duration = 1000L
isElevationShadowEnabled = false
interpolator = DecelerateInterpolator()
}
val manager: FragmentManager = activity.supportFragmentManager
manager.beginTransaction()
.setReorderingAllowed(true)
.addSharedElement(imageView, imageView.transitionName)
.addSharedElement(textView, textView.transitionName)
.addToBackStack(null)
.replace([...])
.commit()
SOLUTION
You can change transition like this:
fragmentEnd.sharedElementEnterTransition = getTransition()
fragmentEnd.sharedElementReturnTransition = getTransition()
private fun getTransition(): Transition{
val set = TransitionSet()
set.ordering = TransitionSet.ORDERING_TOGETHER
set.addTransition(ChangeBounds())
set.addTransition(ChangeImageTransform())
set.addTransition(ChangeTransform())
return set
}
Proper way of using MaterialContainerTransform:
Share one element
fragmentEnd.sharedElementEnterTransition = MaterialContainerTransform().apply {
scrimColor = Color.TRANSPARENT
containerColor = ResourcesCompat.getColor(activity.resources,R.color.purple_amethyst,null)
duration = 1000L
startShapeAppearanceModel = ShapeAppearanceModel().withCornerSize(100f)
interpolator = DecelerateInterpolator()
}
fragmentEnd.sharedElementReturnTransition = MaterialContainerTransform().apply {
scrimColor = Color.TRANSPARENT
containerColor = ResourcesCompat.getColor(activity.resources,R.color.purple_amethyst,null)
duration = 1000L
endShapeAppearanceModel = ShapeAppearanceModel().withCornerSize(100f)
interpolator = DecelerateInterpolator()
}
val manager: FragmentManager = activity.supportFragmentManager
manager.beginTransaction()
.setReorderingAllowed(true)
.addSharedElement(imageView, imageView.transitionName)
.addToBackStack(null)
.replace([...])
.commit()
FragmentEnd Layout:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/container"
android:background="@color/purple_amethyst">
<....../>
</androidx.constraintlayout.widget.ConstraintLayout>
Set transition name to top layout of fragmentEnd
ViewCompat.setTransitionName(binding.container, getArguments().getString("imageViewTransitionName"));
RESULT
Upvotes: 1