Android Support Library 27.1.0共享元素转场返回位置异常求助
解决Support Library 27.1.0共享元素转场返回时ImageView位置异常问题
这种偶发的共享元素转场错位问题,我之前在Support Library版本迭代中确实碰到过类似的坑——尤其是小版本升级里的隐性变更,官方release notes往往不会写这么细。结合我的经验,给你几个排查和修复的方向:
1. 确保列表容器的布局状态完全恢复
从详情页返回时,如果列表(比如RecyclerView)还没滚回转场前的位置,或者目标item还没完成布局测量,共享元素的位置计算就容易出错。你可以这么做:
- 在列表页重写
onActivityReenter方法,先滚动到目标item,再延迟启动转场,给布局留足时间:
@Override public void onActivityReenter(int resultCode, Intent data) { super.onActivityReenter(resultCode, data); // 记得提前记录好转场前的目标item位置 if (targetItemPosition != -1) { mRecyclerView.scrollToPosition(targetItemPosition); // 延迟一小段时间,确保item布局完成后再恢复转场 mRecyclerView.post(() -> { supportPostponeEnterTransition(); supportStartPostponedEnterTransition(); }); } }
- 同时检查item的父布局,确保没有设置
android:clipChildren="true"或者android:clipToPadding="true"限制ImageView的绘制范围,这也可能导致位置计算被截断。
2. 重新规范TransitionName的绑定逻辑
27.1.0可能调整了TransitionName的校验时机,建议你:
- 在列表Adapter的
onBindViewHolder里,给每个item的ImageView设置唯一且固定的transitionName(比如用item的ID做后缀),不要只在ViewHolder创建时设置:
@Override public void onBindViewHolder(ItemViewHolder holder, int position) { ItemModel item = mDataList.get(position); holder.mImageView.setTransitionName("shared_img_" + item.getId()); // 其他数据绑定逻辑... }
- 跳转详情页时,确保Intent里携带了这个transitionName,返回时列表页能精准找到对应的ImageView。
3. 自定义共享元素转场动画替换默认实现
27.1.0可能修改了默认ChangeBounds动画的位置计算逻辑,你可以自定义转场来规避这个问题:
- 写一个继承自
ChangeBounds的自定义转场,强制确保动画的起始位置准确:
public class FixedChangeBounds extends ChangeBounds { @Override public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) { Animator animator = super.createAnimator(sceneRoot, startValues, endValues); if (animator != null) { animator.setDuration(300); // 保持和默认转场一致的时长 animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { // 强制目标View重新布局,确保位置准确 endValues.view.requestLayout(); } }); } return animator; } }
- 在列表页和详情页的转场设置中,替换默认的ChangeBounds:
TransitionSet returnTransition = new TransitionSet(); returnTransition.addTransition(new FixedChangeBounds()); getWindow().setSharedElementReturnTransition(returnTransition);
4. 临时禁用RecyclerView的视图缓存
如果你的RecyclerView设置了较大的itemViewCacheSize,可能导致转场时复用的View状态异常。可以试试:
- 跳转详情页前临时清空缓存,返回后再恢复:
// 跳转前记录原缓存大小 int originalCacheSize = mRecyclerView.getItemViewCacheSize(); mRecyclerView.setItemViewCacheSize(0); // 启动详情页 Intent detailIntent = new Intent(this, DetailActivity.class); ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, targetImageView, transitionName); startActivity(detailIntent, options.toBundle()); // 恢复缓存大小 mRecyclerView.setItemViewCacheSize(originalCacheSize);
我建议你先试试第一种方案,延迟启动转场是解决这类偶发布局时机问题最直接的方法。如果还是不行,再依次排查后面的方向。
内容的提问来源于stack exchange,提问作者Edmund Johnson
相关产品推荐
相关产品推荐

