具有 scaleType centerCrop 过渡的共享元素是跳跃的
Shared Element with scaleType centerCrop transition is jumpy
当 2 ImageViews
从一个屏幕转到下一个屏幕时,我正在尝试实现共享元素转换。其中一张图像在两个屏幕上的 scaleType 均为 centerCrop
。我面临的问题是,当过渡开始时,图像将在将其动画化到下一个屏幕之前变为原始大小(裁剪之前)。当它到达下一个屏幕时,它以原始大小到达它,然后才被裁剪到目标图像视图。
整个体验并不流畅,而且真的让人眼花缭乱。
我使用的代码是:
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());
}
图像是使用 Glide
从网络加载的,代码如下:
Glide.with(mActivity).load(articleCoverData.mImageUrl).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.SOURCE).dontTransform().into(holder.coverImage);
在接收方,图像加载如下:
Glide.with(mContext).load(mData.mImageUrl).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.SOURCE).into(mCoverImageView);
在我定义的样式中:
<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>
当change_image_transform
为:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeImageTransform/>
</transitionSet>
编辑: 尝试将过渡更改为:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeBounds/>
<changeTransform/>
<changeImageTransform/>
</transitionSet>
或
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeBounds/>
<changeImageTransform/>
</transitionSet>
但是结果是一样的
问题是:我是不是漏掉了什么,我还需要做些什么来让这种体验变得窒息吗?或者这是一个 Android 错误?
在你的change_image_transform.xml中,改成这个
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeImageTransform/>
<changeBounds/>
</transitionSet>
终于解决了这个问题。使用以下代码和配置实现了预期的结果:
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());
}
我正在使用 Picasso 和以下代码将图像加载到图像视图中:
Picasso.with(mActivity).load(articleCoverData.mImageUrl).into(articleVH.coverImage);
在接收方,我以相同的方式应用图像:
Picasso.with(mContext).load(mData.mImageUrl).into(mCoverImageView);
风格:
<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>
两个转换:cheeses_enter
和 cheeses_exit
是:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet>
<changeBounds />
<changeTransform />
<changeClipBounds />
<changeImageTransform />
</transitionSet>
重要的是使用 ImageView scaleType 参数应用缩放类型,而不是使用 Picasso 裁剪或 Glide 裁剪。
因为如果您这样做,裁剪和取消裁剪操作将作为过渡的一部分执行。
只是为了给遇到这个问题的任何人一个答案(以及更多的解释)。
首先,只需使用 <changeImageTransform/>
和 <changeBounds/>
就足以完成转换。
问题主要是 Glide 如何随着时间的推移处理 imageview/drawable 测量。有一些延迟,因此没有创建过渡动画。
Picasso 根据 scaletype
和过渡效果足够快地提供图像(矩阵)的位置值。
我遇到了同样的问题,我已经在我的 Glide
加载请求中使用了 dontAnimate() + dontTransform()
。
对我来说,我的解决方案是 删除:
clipToPadding="false"
clipChildren="false"
来自我的 ImageView 的容器 ViewGroup。
在共享元素转换期间使用 scaleType="centerCrop"
时,这些属性使我的图像未被剪裁。
当 2 ImageViews
从一个屏幕转到下一个屏幕时,我正在尝试实现共享元素转换。其中一张图像在两个屏幕上的 scaleType 均为 centerCrop
。我面临的问题是,当过渡开始时,图像将在将其动画化到下一个屏幕之前变为原始大小(裁剪之前)。当它到达下一个屏幕时,它以原始大小到达它,然后才被裁剪到目标图像视图。
整个体验并不流畅,而且真的让人眼花缭乱。 我使用的代码是:
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());
}
图像是使用 Glide
从网络加载的,代码如下:
Glide.with(mActivity).load(articleCoverData.mImageUrl).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.SOURCE).dontTransform().into(holder.coverImage);
在接收方,图像加载如下:
Glide.with(mContext).load(mData.mImageUrl).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.SOURCE).into(mCoverImageView);
在我定义的样式中:
<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>
当change_image_transform
为:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeImageTransform/>
</transitionSet>
编辑: 尝试将过渡更改为:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeBounds/>
<changeTransform/>
<changeImageTransform/>
</transitionSet>
或
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeBounds/>
<changeImageTransform/>
</transitionSet>
但是结果是一样的
问题是:我是不是漏掉了什么,我还需要做些什么来让这种体验变得窒息吗?或者这是一个 Android 错误?
在你的change_image_transform.xml中,改成这个
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeImageTransform/>
<changeBounds/>
</transitionSet>
终于解决了这个问题。使用以下代码和配置实现了预期的结果:
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());
}
我正在使用 Picasso 和以下代码将图像加载到图像视图中:
Picasso.with(mActivity).load(articleCoverData.mImageUrl).into(articleVH.coverImage);
在接收方,我以相同的方式应用图像:
Picasso.with(mContext).load(mData.mImageUrl).into(mCoverImageView);
风格:
<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>
两个转换:cheeses_enter
和 cheeses_exit
是:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet>
<changeBounds />
<changeTransform />
<changeClipBounds />
<changeImageTransform />
</transitionSet>
重要的是使用 ImageView scaleType 参数应用缩放类型,而不是使用 Picasso 裁剪或 Glide 裁剪。
因为如果您这样做,裁剪和取消裁剪操作将作为过渡的一部分执行。
只是为了给遇到这个问题的任何人一个答案(以及更多的解释)。
首先,只需使用 <changeImageTransform/>
和 <changeBounds/>
就足以完成转换。
问题主要是 Glide 如何随着时间的推移处理 imageview/drawable 测量。有一些延迟,因此没有创建过渡动画。
Picasso 根据 scaletype
和过渡效果足够快地提供图像(矩阵)的位置值。
我遇到了同样的问题,我已经在我的 Glide
加载请求中使用了 dontAnimate() + dontTransform()
。
对我来说,我的解决方案是 删除:
clipToPadding="false"
clipChildren="false"
来自我的 ImageView 的容器 ViewGroup。
在共享元素转换期间使用 scaleType="centerCrop"
时,这些属性使我的图像未被剪裁。