只有在被选中时才在 ViewPager 中加载片段

Posted

技术标签:

【中文标题】只有在被选中时才在 ViewPager 中加载片段【英文标题】:load fragment in ViewPager only when its selected 【发布时间】:2018-05-09 09:04:10 【问题描述】:

我有一个带有 3 个标签的 ViewPager。

我在每个片段中加载大数据。

应用程序会加载每个片段,但我只想在片段被选中时才加载片段。

我该怎么做?我不知道。 我在等你的帮助。谢谢

我的代码:

public class Fragments extends AppCompatActivity 

    private TabLayout tabLayout;
    private ViewPager viewPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_tabs);

        viewPager = (ViewPager) findViewById(R.id.viewpager);
        setupViewPager(viewPager);

        tabLayout = (TabLayout) findViewById(R.id.tabs);
        tabLayout.setupWithViewPager(viewPager);
    

    private void setupViewPager(ViewPager viewPager) 
        ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
        adapter.addFragment(new FirstFragment(), "1");
        adapter.addFragment(new SecondFragment(), "2");
        adapter.addFragment(new ThirdFragment(), "3");
        viewPager.setAdapter(adapter);
    

    class ViewPagerAdapter extends FragmentPagerAdapter 
        private final List<Fragment> mFragmentList = new ArrayList<>();
        private final List<String> mFragmentTitleList = new ArrayList<>();

        public ViewPagerAdapter(FragmentManager manager) 
            super(manager);
        

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

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

        public void addFragment(Fragment fragment, String title) 
            mFragmentList.add(fragment);
            mFragmentTitleList.add(title);
        

        @Override
        public CharSequence getPageTitle(int position) 
            return mFragmentTitleList.get(position);
        
    

【问题讨论】:

【参考方案1】:

如果没有人给你一个好的答案,我知道这是 5 年后,但任何人都在读这篇文章。我实际上遇到了相反的问题。我需要同时加载所有标签。现在发生在我身上的是一次只加载一个标签。我需要将此适配器用于带有 tablayout 的 viewpager2,以便我可以针对我的特定用例禁用从左到右滑动的 viewpager。

这是我的代码:

警告代码在 KOTLIN 而非 JAVA 中

class RecipeTabAdapter internal constructor(fm: FragmentManager, lifecycle: Lifecycle) : FragmentStateAdapter(fm, lifecycle) 

val fragmentsList: ArrayList<Fragment> = arrayListOf()

fun addFragment(fragment: Fragment) 
    fragmentsList.add(fragment)


override fun getItemCount(): Int 
    return fragmentsList.size


override fun createFragment(position: Int): Fragment 
    when (position) 
        position -> fragmentsList[position]
        position -> fragmentsList[position]
    
    return fragmentsList[position]

【讨论】:

【参考方案2】:

是否可以禁用离屏页面限制?

没有。它已设置为可能的最小值:查看页面的每一侧都有一个页面。这是使动画效果发挥作用所必需的——您可以同时看到两个片段(原始片段和新片段)的一部分。

【讨论】:

【参考方案3】:

OncreateView()

//.... dont initialize your view here

if(isMenuVisible())  // menu should be visible if current fragment is visible right now
            setUserVisibleHint(true); // manually set value to true
        


 oncreate()

setHasOptionsMenu(true);


最后有一个名为 setuservisiblehint() 的方法,该方法仅在片段对用户可见时调用,这是您初始化所有视图的唯一方法。

@Override
    public void setUserVisibleHint(boolean isVisibleToUser) 
        super.setUserVisibleHint(isVisibleToUser);

        if(isVisibleToUser && v != null) 

              // initialize your view here and call you fetch_data_function()


【讨论】:

【参考方案4】:

这是我的解决方案,它按预期工作。在您的所有子片段中创建一个boolean 变量:

private boolean loadFragmentExecuted = false;

在子片段中创建一个名为 loadFragment 的通用方法,并将您在 onCreateView 中添加的所有逻辑移至该方法:

public void loadFragment()

    if(!loadFragmentExecuted)
    
        //Add your logic to manipulate the UI or load data etc...
        loadFragmentExecuted = true;
    

在您的网页浏览逻辑中动态创建片段,例如:

//add the fragment
String fragmentName = "com.something." + fragmentId;

//check if the class exists
try

    Class myFragmentClass = Class.forName(fragmentName);
    Fragment myFragment = (Fragment) myFragmentClass.newInstance();
    mFragments.add(myFragment);

catch (ClassNotFoundException e)

    e.printStackTrace();

catch (IllegalAccessException e)

    e.printStackTrace();

catch (InstantiationException e)

    e.printStackTrace();

然后设置您的寻呼机适配器并附上一个tablayout:

//set our pager adapter that contains different fragments
mPagerAdapter = new BasePagerAdapter(mFragmentManager, mFragments);

//link the adapter to the viewpager
mViewPager.setAdapter(mPagerAdapter);

//cache fragments
int limit = (mPagerAdapter.getCount() > 0 ? mPagerAdapter.getCount() : 1);
mViewPager.setOffscreenPageLimit(limit);

//add the page listner to the viewPager and link it to the tabLayout
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout));

//on tab selected select current viewpager item
mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener()

    @Override
    public void onTabSelected(TabLayout.Tab tab)
    
        mViewPager.setCurrentItem(tab.getPosition());

        //get fragment for the selected tab
        Fragment f = mPagerAdapter.getItem(tab.getPosition());

        //load the content of the fragment
        try
        
            Class c = f.getClass();
            Method loadFragment = c.getMethod("loadFragment");
            loadFragment.invoke(f);
        
        catch (IllegalAccessException e)
        catch (InvocationTargetException e)
        catch (NoSuchMethodException e)
    

    @Override
    public void onTabUnselected(TabLayout.Tab tab)
    
    

    @Override
    public void onTabReselected(TabLayout.Tab tab)
    
    
);

【讨论】:

【参考方案5】:

我有一个不需要子类化的解决方案,并且很容易引入到现有项目中。它使用子片段机制。

基本思想是用几乎空的片段替换您的内容片段,并在用户真正可见时将您的内容片段添加为子片段

代码的要点是这样的

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) 
    super.onViewCreated(view, savedInstanceState);

    boolean hasFragment = getChildFragmentManager().findFragmentById(R.id.container) != null;
    if (hasFragment) 
        return;
    

    if (getUserVisibleHint()) 
        addFragment("onViewCreated");
    


@Override
public void onResume() 
    super.onResume();

    if (getUserVisibleHint()) 
        addFragment("onResume");
    


@Override
public void setUserVisibleHint(boolean isVisibleToUser) 
    super.setUserVisibleHint(isVisibleToUser);

    if (isVisibleToUser && isResumed()) 
        addFragment("setUserVisibleHint");
    




private void addFragment(String cause) 
    if (getChildFragmentManager().findFragmentById(R.id.container) == null) 
        getChildFragmentManager().beginTransaction()
                .setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out)
                .add(R.id.container, createFragment()).commit();

    

在此处查看我的完整解决方案,其中还包含一个进度条,以及以指定延迟自动开始加载背景片段的选项:Lazy Load Fragment

【讨论】:

这行不通。由于 onResume 已经被调用,并且 isVisibleToUser 仅在用户可见时才为真,因此不会满足此条件,因此它不是解决方案。

以上是关于只有在被选中时才在 ViewPager 中加载片段的主要内容,如果未能解决你的问题,请参考以下文章

在ViewPager中看不到碎片

[Android] Android ViewPager 中加载 Fragmenet的几种方式

将 ViewPager 与 Fragments 一起使用时,在滑动时会破坏 Fragment

我无法在片段中加载数据 json

在一个活动中加载单个片段两次,从本地json文件中加载2个问题

在活动OnCreate中加载片段