防止 ViewPager 破坏屏幕外视图

Posted

技术标签:

【中文标题】防止 ViewPager 破坏屏幕外视图【英文标题】:Prevent ViewPager from destroying off-screen views 【发布时间】:2012-01-11 00:46:54 【问题描述】:

我有一个 ViewPager 连接到一个显示三个片段的 FragmentPagerAdapter。当 ViewPager 从当前位置滑动不止一次时,它似乎会破坏托管片段的视图。

这些视图都是简单的列表,完全不需要这种优化,所以我想禁用它。这会导致一些视觉问题,因为列表应用了布局动画,并且这些动画在它们被销毁和重新创建后会被重播。它还每次显示滚动条介绍动画(滚动条短暂可见以指示可以滚动),这可能会分散注意力,并且在此过程中会丢失用户当前的滚动位置。

在第一次滑动之前它也不会加载第三个片段,这是有问题的,因为每个片段都处理自己的服务调用,我希望在活动加载时同时触发所有三个片段。延迟第三次服务调用并不理想。

有什么方法可以说服 ViewPager 停止这种行为,只将我所有的片段保存在内存中?

【问题讨论】:

【参考方案1】:

在支持包的revision 4 中,向 ViewPager 添加了一个方法,该方法允许您指定要使用的离屏页面数,而不是默认值 1。

在你的情况下,你想指定 2,这样当你在第三页时,第一个不会被破坏,反之亦然。

mViewPager = (ViewPager)findViewById(R.id.pager);
mViewPager.setOffscreenPageLimit(2);

【讨论】:

知道如何在封面流上执行此操作吗? 你好。在我的工作中,片段/页面是动态创建的,因此可能的片段数量不定。在这种情况下,它通常会达到 10 或更少。对那么多页面使用这个解决方案会不会是内存使用不当?顺便说一句,片段只会保留视图。谢谢! 这个方法抛出:“java.lang.IllegalStateException: Fragment already added:”我的应用出错。 非常感谢。它真的奏效了。我也有像@chefgon 一样的问题。 @mahie 上述解决方案如果作为优化提供的话。如果您事先知道需要支持的页面数* 或在页面上设置延迟加载机制*,则调整此设置可以提高分页动画和交互的感知平滑度*。如果您有少量页面 (3-4) * 您可以一次保持活动状态,则在用户页面来回切换时新创建的视图子树的布局将花费更少的时间【参考方案2】:

默认情况下,ViewPager 会在您滑动页面时重新创建片段。为了防止这种情况,您可以尝试以下两种方法之一:

1. 在片段的 onCreate() 中,调用 setRetainInstance(true)。

2.如果片段数量固定且相对较少,则在您的 onCreate() 中添加以下代码:

ViewPager mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setOffscreenPageLimit(3);

如果我没记错的话,第二种选择更有希望。但我强烈建议您尝试这两种方法,看看哪一种有效。

【讨论】:

【参考方案3】:

“设置应保留到处于空闲状态的视图层次结构中当前页面的任一侧的页面数。超出此限制的页面将在需要时从适配器重新创建。”

http://developer.android.com/reference/android/support/v4/view/ViewPager.html#setOffscreenPageLimit(int)

【讨论】:

【参考方案4】:

选择的答案很好,但对我来说并不是很好。这是因为我有很多片段 (20-30),因此如果我使用 setOffscreenPageLimit(30),使用 ViewPager 的活动将需要很长时间才能加载。在我的情况下,我必须实现 destroyItem() 方法(在 ViewPager 的 Adapter 类中)并删除对超级函数的调用。这是伪代码

@Override                                                                                    
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) 
                                                                                             
                                                                                            

如果你想要更多的上下文,这里是整个 ViewPagerAdapter 类

public class ViewPagerAdapter extends FragmentPagerAdapter 
    private final List<Fragment> listFragment =
            new ArrayList<>();
    public ViewPagerAdapter(@NonNull FragmentManager fm) 
        super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
    

    @NonNull
    @Override
    public Fragment getItem(int position) 
        return listFragment.get(position);
    

    @Override
    public int getCount() 
        return listFragment.size();
    

    /*This is the method I was taking about*/
    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) 
    
    

    public void addFragment(Fragment fragment)
    
        listFragment.add(fragment);
        notifyDataSetChanged();
    

【讨论】:

是的,这就是我正在寻找的答案。谢谢!

以上是关于防止 ViewPager 破坏屏幕外视图的主要内容,如果未能解决你的问题,请参考以下文章

Fragment防止自动清理 (ViewPager滑动时,滑出屏幕后被清理)(转)

防止屏幕外的div调整大小

具有上一页和下一页边界的 ViewPager

ViewPager 片段随着时间的推移而被破坏?

从互联网加载图像后,Viewpager 不包装内容

如何在屏幕外剪辑 ImageView 的角(圆角)