Pew*_*chu 5 animation android shared-element-transition android-glide
请注意,这个问题与此处找到的问题非常相似。没有解决方案,所以我想我应该提供一些代码并再次询问。
本质上,我试图在两个片段之间进行 ImageView 的共享元素转换。我的最终目标是制作一个看起来与默认图片库非常相似的动画。重要的一点是我使用 Glide 来加载图像。我遇到的问题是我无法让scaleType 平滑地进行动画处理(从centerCrop 到fitCenter)。
我有一个包含 RecyclerView 的片段,其每个项目都包含一个 ImageView。这些 ImageView 是缩略图,XML 如下所示:
<ImageView
android:id="@+id/ivPhoto"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/large_spacing"
android:scaleType="centerCrop"/>
Run Code Online (Sandbox Code Playgroud)
重要/有问题的部分是scaleType="centerCrop"
我使用以下命令设置转换名称并在 RecyclerView 适配器中加载图像:
holder.ivPhoto.setTransitionName(current.getPhotoFilepath());
Glide.with(holder.ivPhoto.getContext())
.load(current.getPhotoFilepath())
.dontTransform()
.into(holder.ivPhoto);
Run Code Online (Sandbox Code Playgroud)
单击某个项目时,将运行以下代码:
@Override
public void onItemClicked(AssetDetail assetDetail, ImageView imageView) {
if (assetDetail.getPhotoFilepath() != null) {
AssetDetailFragmentDirections.ActionAssetDetailFragmentToDisplayImageFragment action = AssetDetailFragmentDirections.actionAssetDetailFragmentToDisplayImageFragment(assetDetail.getPhotoFilepath());
FragmentNavigator.Extras extras = new FragmentNavigator.Extras.Builder()
.addSharedElement(imageView, assetDetail.getPhotoFilepath())
.build();
NavHostFragment.findNavController(this).navigate(action, extras);
}
}
Run Code Online (Sandbox Code Playgroud)
这将带您到第二个片段,它基本上只包含以下 ImageView(技术上是 PhotoView,我也尝试过使用普通 ImageView):
<com.github.chrisbanes.photoview.PhotoView
android:id="@+id/ivImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:adjustViewBounds="true"
android:scaleType="fitCenter" />
Run Code Online (Sandbox Code Playgroud)
我推迟输入转换并设置我想要使用的转换:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
postponeEnterTransition();
TransitionSet transitionSet = new TransitionSet()
.addTransition(new ChangeBounds())
.addTransition(new ChangeImageTransform())
.setDuration(1500)
.setOrdering(TransitionSet.ORDERING_TOGETHER)
.setInterpolator(new FastOutSlowInInterpolator());
setSharedElementEnterTransition(transitionSet);
}
Run Code Online (Sandbox Code Playgroud)
最后,我获取并设置转换名称,加载图像并启动推迟的输入转换:
DisplayImageFragmentArgs args = DisplayImageFragmentArgs.fromBundle(getArguments());
binding.ivImage.setTransitionName(args.getImageFilepath());
Glide.with(requireContext())
.load(args.getImageFilepath())
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
startPostponedEnterTransition();
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
startPostponedEnterTransition();
return false;
}
})
.dontTransform()
.into(binding.ivImage);
Run Code Online (Sandbox Code Playgroud)
这导致这个动画是完全错误的。
如果我像这样交换转换的顺序:
TransitionSet transitionSet = new TransitionSet()
.addTransition(new ChangeImageTransform())
.addTransition(new ChangeBounds())
.setDuration(1500)
.setOrdering(TransitionSet.ORDERING_TOGETHER)
.setInterpolator(new FastOutSlowInInterpolator());
Run Code Online (Sandbox Code Playgroud)
我得到的动画更接近,但是输入过渡从一个奇怪的地方开始,并且返回过渡位于保存 ImageView 的 CardView 后面/内部。
尝试一些不同的转换(根据本文)
TransitionSet transitionSet = new TransitionSet()
.addTransition(new ChangeClipBounds())
.addTransition(new ChangeTransform())
.addTransition(new ChangeBounds())
.setDuration(1500)
.setOrdering(TransitionSet.ORDERING_TOGETHER)
.setInterpolator(new FastOutSlowInInterpolator());
Run Code Online (Sandbox Code Playgroud)
结果是这样的。在此示例中,您可以看到scaleType 立即发生变化,然后动画的其余部分发生。我希望 scaleType 的更改能够与其他所有内容一起平滑地进行动画处理。
最终过渡组合的一个有趣的点是,如果我scaleType="centerCrop"从 RecyclerView 中的 ImageView 中删除它,它的动画效果会完美,但显然这意味着图像具有原始的宽高比,并且不是正确的缩略图。看这里。
这个问题显然与scaleType有关,但无论我尝试什么,我似乎都无法让它工作。我已经进行了大量的谷歌搜索和阅读,但没有发现任何可以解决问题的方法。
据我了解,使用 ChangeImageTransform 应该为scaleType设置动画,但是将它与我尝试过的任何组合(比这里列出的更多,包括与 ChangeTransform 一起尝试)似乎不起作用,或者至少不完全是我想要/期望的那样。此时我已经非常沮丧了。
如果有人能给我任何帮助来解决这个问题,我将不胜感激。
最简单的解决方案可能是切换到 Picasso 而不是 Glide,因为具有scaleType centerCrop 转换的共享元素的询问者最终会变得神经兮兮。
问题在于 Glide 调整图像大小以适合每个 ImageView 以节省内存的方式。如果缩略图 ImageView 大小与 ViewPager 大小不同,则会破坏共享元素转换的 ChangeImageTransform。
首先,您的转换集应包含:
<changeClipBounds/>
<changeTransform/>
<changeBounds/>
<changeImageTransform/>
Run Code Online (Sandbox Code Playgroud)
关键是添加到 Glide 请求中:
.dontTransform()
.override(screenWidth, screenHeight)
Run Code Online (Sandbox Code Playgroud)
但是,这将导致 Grid 片段占用大量内存,因为每个图像的加载大小都比缩略图所需的大小大得多。您会遇到滚动缓慢和崩溃的情况。
因此,您可以默认情况下以旧方式加载图像,然后在单击网格项时在转换之前加载全屏大小的图像。您还需要推迟 Pager 片段事务,直到加载完整图像,以便转换可以快照新的 ImageView 属性。
onClickGridItem() {
Glide.with(imageView)
.load(uri)
.listener(RequestListener<Drawable> {
onResourceReady() {
openPagerFragment()
return false
}
})
.dontTransform()
.override(screenWidth, screenHeight)
.into(imageView)
}
Run Code Online (Sandbox Code Playgroud)
在图像尺寸之间交换时,这可能会导致不必要的闪烁。您可以通过在将全尺寸图像设置到 ImageView 之前预加载全尺寸图像来避免这种情况:
Glide.with(imageView)
.load(uri)
.listener(RequestListener<Drawable> {
onResourceReady() {
Glide.with ... .override(screenWidth, screenHeight).into(imageView)
return false
}
})
.dontTransform()
.preload(screenWidth, screenHeight)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1218 次 |
| 最近记录: |