RecyclerView跳转带ViewPager的Activity时共享元素转场闪烁问题求助
我来帮你分析下这个共享元素转场闪烁的问题,从你的代码里能看到几个关键问题,咱们一步步解决:
1. 修复共享元素TransitionName不匹配的核心问题
这是导致转场闪烁最常见的原因!你在MainActivity里给ImageView设置的过渡名称是MainActivity.position + "ZoomImage",但在Fragment里设置的是MainActivity.position + "ImageZoom"——两个字符串的后缀顺序完全反了,系统根本找不到对应的共享元素,自然会出现闪烁。
解决方案:统一两边的TransitionName
在MainActivity跳转时,设置统一的过渡名称:
Intent myIntent = new Intent(getActive, EnlargeActivity.class); myIntent.putExtra("IMAGE_URL", imageArrayList.get(position).getUrl()); myIntent.putExtra("POSITION", position); // 顺便把position通过Intent传递,替代静态变量 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { String transitionName = "zoom_image_" + position; holder.iv.setTransitionName(transitionName); ActivityOptionsCompat options = ActivityOptionsCompat .makeSceneTransitionAnimation(getActive, holder.iv, transitionName); context.startActivity(myIntent, options.toBundle()); }
在Fragment的Picasso回调里,使用同样的过渡名称:
// 从EnlargeActivity获取传递过来的position,避免静态变量的不可靠性 int currentPosition = ((EnlargeActivity) getActivity()).getIntent().getIntExtra("POSITION", 0); String transitionName = "zoom_image_" + currentPosition; Picasso.with(getActivity()) .load(url) .into(imageView, new Callback() { @Override public void onSuccess() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { imageView.setTransitionName(transitionName); } getActivity().supportStartPostponedEnterTransition(); } @Override public void onError() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { imageView.setTransitionName(transitionName); } getActivity().supportStartPostponedEnterTransition(); } });
2. 优化PostponeEnterTransition的使用逻辑
你已经用了supportPostponeEnterTransition()来等待图片加载,但要确保ViewPager已经切换到了目标Fragment(即当前position对应的页面),不然图片还没准备好就开始转场,也会闪烁。
解决方案:确保ViewPager先切换到目标页面再等待加载
在EnlargeActivity的onCreate里,初始化ViewPager后先设置当前页面:
super.onCreate(savedInstanceState); setContentView(R.layout.activity_enlarge); int currentPosition = getIntent().getIntExtra("POSITION", 0); ViewPager viewPager = findViewById(R.id.your_viewpager_id); // 初始化适配器 viewPager.setAdapter(yourAdapter); // 先切换到目标页面 viewPager.setCurrentItem(currentPosition); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // 不要直接设置enterTransition为null,改为配置共享元素过渡 getWindow().setEnterTransition(new Fade().setDuration(0)); // 取消非共享元素的进入过渡 getWindow().setSharedElementEnterTransition(new ChangeBounds()); // 保留共享元素的边界变化过渡 } supportPostponeEnterTransition();
3. 替换静态变量传递position的方式
你用MainActivity.position这个静态变量来存当前位置,在快速滑动、配置变化(比如旋转屏幕)时很容易出现值不准确的情况,导致TransitionName错误。改用Intent传递position是更可靠的方式,上面的代码已经包含了这部分修改。
4. 确保ImageView的ScaleType一致
检查RecyclerView中的ImageView和Fragment中的ImageView的ScaleType是否完全相同(比如都是CENTER_CROP)。如果ScaleType不一样,转场时图片的显示尺寸、裁剪方式会突变,视觉上就会出现闪烁。
5. Picasso加载优化(减少加载延迟)
给Picasso添加缓存策略,优先使用本地缓存加载图片,减少等待时间:
Picasso.with(getActivity()) .load(url) .memoryPolicy(MemoryPolicy.CACHE) // 优先使用内存缓存 .networkPolicy(NetworkPolicy.CACHE) // 优先使用磁盘缓存 .into(imageView, new Callback() { // 回调代码不变 });
按照上面的步骤逐一修改后,共享元素转场的闪烁问题应该就能解决了。
内容的提问来源于stack exchange,提问作者blackHawk

