I'm trying to implement a shared elements transition when 2 ImageViews
from one screen go to the next screen. one of the images has a scaleType of centerCrop
on both screen. The problem I'm facing is that when the transition starts the image is going to it's original size (before the crop) just before the animating it to the next screen. when it's reaches the next screen it reaches it with it's original size and only then it's cropped to the target image view.
The whole experience is not smooth and really jumpy to the eye. The code I use is:
public void animateIntent(View view, ArticleCoverData articleCoverData) {
Intent intent = new Intent(mActivity, ReaderActivity.class);
intent.putExtra(Constants.ARTICLE_DATA, articleCoverData);
// The view animation will start from
View coverStartView = view.findViewById(R.id.coverImage);
View coverDiagonalDecoratorStartView = view.findViewById(R.id.diagonal_image_decorator);
Pair<View, String> pair1 = Pair.create(coverStartView, mActivity.getString(R.string.transition_timeline_cover_image_to_reader_name));
Pair<View, String> pair2 = Pair.create(coverDiagonalDecoratorStartView, mActivity.getString(R.string.transition_timeline_cover_image_diagonal_decorator_to_reader_name));
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(mActivity, pair1, pair2);
ActivityCompat.startActivity(mActivity, intent, options.toBundle());
}
The image is loaded from the web using Glide
with following code:
Glide.with(mActivity).load(articleCoverData.mImageUrl).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.SOURCE).dontTransform().into(holder.coverImage);
On the receiving side the image is loaded as follows:
Glide.with(mContext).load(mData.mImageUrl).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.SOURCE).into(mCoverImageView);
In the style I defined:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Add this line -->
<item name="android:windowContentTransitions">true</item>
<!-- This is the color of the Status bar -->
<item name="colorPrimaryDark">@color/transparent</item>
<!-- specify shared element transitions -->
<item name="android:windowSharedElementEnterTransition">
@transition/change_image_transform</item>
<item name="android:windowSharedElementExitTransition">
@transition/change_image_transform</item>
</style>
When change_image_transform
is:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeImageTransform/>
</transitionSet>
Edit: Tried to change the transition to:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeBounds/>
<changeTransform/>
<changeImageTransform/>
</transitionSet>
or
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeBounds/>
<changeImageTransform/>
</transitionSet>
But the result is the same.
The question is: Am I missing something here, is there something else I need to do to make this experience smother? or this is an Android bug?
Finally, managed to solve this issue. desired result was achieved using the following code and configuration:
private static void startAnimatedTransitionIntent(Activity context, View view, ArticleCoverData articleCoverData) {
Intent intent = new Intent(context, ReaderActivity.class);
intent.putExtra(Constants.ARTICLE_DATA, articleCoverData);
View coverStartView = view.findViewById(R.id.coverImage);
View coverDiagonalDecoratorStartView = view.findViewById(R.id.diagonal_image_decorator);
Window window = context.getWindow();
View decor = window.getDecorView();
View navigationBarStartView = decor.findViewById(android.R.id.navigationBarBackground);
List<Pair<View, String>> pairs = new ArrayList<>();
pairs.add(Pair.create(coverStartView, context.getString(R.string.transition_timeline_cover_image_to_reader_name)));
pairs.add(Pair.create(coverDiagonalDecoratorStartView, context.getString(R.string.transition_timeline_cover_image_diagonal_decorator_to_reader_name)));
if (navigationBarStartView != null) {
pairs.add(Pair.create(navigationBarStartView, Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME));
}
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(context, pairs.toArray(new Pair[pairs.size()]));
ActivityCompat.startActivity(context, intent, options.toBundle());
}
I'm loading the images into the image view using Picasso and the following code:
Picasso.with(mActivity).load(articleCoverData.mImageUrl).into(articleVH.coverImage);
On the receiving side I apply the image in the same way:
Picasso.with(mContext).load(mData.mImageUrl).into(mCoverImageView);
The style:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:statusBarColor">@color/app_red</item>
<item name="android:windowContentTransitions">true</item>
<!-- This is the color of the Status bar -->
<item name="colorPrimaryDark">@color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<!--<item name="android:windowEnterTransition">@transition/cheeses_enter</item>-->
<!--<item name="android:windowExitTransition">@transition/cheeses_exit</item>-->
<item name="android:windowSharedElementEnterTransition">@transition/cheeses_enter</item>
<item name="android:windowSharedElementExitTransition">@transition/cheeses_exit</item>
</style>
both transitions: cheeses_enter
and cheeses_exit
are:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet>
<changeBounds />
<changeTransform />
<changeClipBounds />
<changeImageTransform />
</transitionSet>
The important thing is to apply your scale type using the ImageView scaleType parameter and not using Picasso crop or Glide crop.
Because if you do that the the crop and the un-crop action would perform as part of the transition.
I am facing the same issue and I already use dontAnimate() + dontTransform()
in my Glide
load request.
For me, my solution is to remove:
clipToPadding="false"
clipChildren="false"
from my ImageView's container ViewGroup.
Those properties leave my image unclipped when using scaleType="centerCrop"
during the Shared element transition.
Just to give an answer (and a bit more explanation) for anyone bumping this problem.
First of all just using <changeImageTransform/>
and <changeBounds/>
is enough to make the transition.
The problem is mainly how Glide handles the imageview/drawable measurement over the time. There is some delay and for this reason no transition animation is created.
Picasso provides quick enough the values of the location of the image (matrix) based on scaletype
and the transitions work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With