返回含StaggeredGridLayoutManager的RecyclerView时共享元素过渡异常求助
解决StaggeredGridLayoutManager下RecyclerView返回时共享元素过渡异常问题
我之前在处理StaggeredGridLayoutManager搭配共享元素过渡时也踩过类似的坑,结合你描述的场景——Item高度随机、返回Activity时过渡异常,给你几个针对性的解决思路:
方法一:保存并恢复Item的高度与布局位置
这个方法的核心是确保返回时RecyclerView的Item布局(高度、位置)和跳转前完全一致,因为StaggeredGridLayoutManager会因Item高度变化重新排列,导致共享元素的起始/结束位置不匹配,进而引发过渡异常。
- 在MainActivity中保存状态:
private HashMap<Integer, Integer> itemHeights = new HashMap<>(); @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // 记录当前可见Item的高度 int[] firstVisiblePositions = staggeredGridLayoutManager.findFirstVisibleItemPositions(null); int[] lastVisiblePositions = staggeredGridLayoutManager.findLastVisibleItemPositions(null); for (int i = firstVisiblePositions[0]; i <= lastVisiblePositions[0]; i++) { RecyclerView.ViewHolder holder = recyclerView.findViewHolderForAdapterPosition(i); if (holder != null) { itemHeights.put(i, holder.itemView.getHeight()); } } // 保存RecyclerView的布局状态 outState.putParcelable("layout_state", staggeredGridLayoutManager.onSaveInstanceState()); outState.putSerializable("item_heights", itemHeights); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); if (savedInstanceState == null) return; // 恢复高度记录集合 itemHeights = (HashMap<Integer, Integer>) savedInstanceState.getSerializable("item_heights"); // 恢复RecyclerView的滚动位置 Parcelable layoutState = savedInstanceState.getParcelable("layout_state"); staggeredGridLayoutManager.onRestoreInstanceState(layoutState); // 通知Adapter更新布局 adapter.notifyDataSetChanged(); }
- 在Adapter中复用保存的高度:
@Override public void onBindViewHolder(ItemViewHolder holder, int position) { // 优先使用跳转前保存的高度,无记录则生成随机高度 int targetHeight = itemHeights.getOrDefault(position, new Random().nextInt(300) + 200); ViewGroup.LayoutParams params = holder.itemView.getLayoutParams(); params.height = targetHeight; holder.itemView.setLayoutParams(params); // 其他Item绑定逻辑(比如设置共享元素的transitionName等) }
方法二:延迟共享元素过渡的触发
有时候过渡异常是因为RecyclerView还没完成重新布局,就开始执行共享元素动画了。我们可以延迟过渡的开始,等布局稳定后再触发:
在MainActivity中重写onEnterAnimationComplete方法,确保布局完成后再恢复过渡:
@Override public void onEnterAnimationComplete() { super.onEnterAnimationComplete(); recyclerView.post(() -> { // 恢复共享元素过渡动画 getWindow().getSharedElementEnterTransition().resume(); }); }
另外,也可以在启动DetailsActivity时,给过渡设置短暂延迟:
// 创建过渡选项时添加延迟 ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, sharedView, transitionName); options.getSharedElementEnterTransition().setStartDelay(100); startActivity(intent, options.toBundle());
方法三:使用固定Item高度(业务允许的情况下)
如果随机高度不是业务必须的,直接给Item设置固定高度是最简单的解决方案。这样StaggeredGridLayoutManager的布局不会因高度变化而重新排列,共享元素的位置匹配就不会出问题。
内容的提问来源于stack exchange,提问作者Anton111111
相关产品推荐
相关产品推荐

