简体   繁体   English

选择不同的选项卡时如何在 ViewPager + TabLayout 中暂停片段?

[英]How to pause a fragment in ViewPager + TabLayout when a different tab is selected?

Right now I have a tablayout with a ViewPager + adapter below it.现在我有一个标签布局,下面有一个 ViewPager + 适配器。 I want to pause a fragment when a different tab is selected (not destroy/pop it, just pause it) and resume it when the fragment's tab is selected.我想在选择不同的选项卡时暂停片段(不是销毁/弹出它,只是暂停它)并在选择片段的选项卡时恢复它。

public class PagerFragment extends Fragment {

    ViewPagerAdapter pagerAdapter;
    ViewPager pager;
    TabLayout tabLayout;
    int position;

    public PagerFragment() {
        super();
    }

    public void setPosition(int position) {
        this.position = position;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onStop() {
        super.onStop();
    }

    @Override
    public void onPause() {
        super.onPause();
        pagerAdapter.clear();
        pagerAdapter.notifyDataSetChanged();
    }

    @Override
    public void onStart() {
        super.onStart();
    }

    @Override
    public void onResume() {
        super.onResume();
        if (!isAdded()) {
            pagerAdapter.instantiateItem(pager, position);
        }
    }

    @SuppressLint("InflateParams")
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_pager, null);
        pagerAdapter = new ViewPagerAdapter(getChildFragmentManager());
        setPosition(position);
        pagerAdapter.setDevicesList(devicesList);
        pager = root.findViewById(R.id.pager);
        pager.setAdapter(pagerAdapter);
       
        tabLayout = root.findViewById(R.id.tab_layout);

        for (int i = 0; i < devicesList.size(); i++) {
            tabLayout.addTab(tabLayout.newTab().setText(String.valueOf(devicesList.get(i).getName())));
        }

        TabLayout.Tab tab = tabLayout.getTabAt(position);
        if (tab != null) {
            tab.select();
            pager.setCurrentItem(position);
            tabLayout.setupWithViewPager(pager);

            tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
                @Override
                public void onTabSelected(TabLayout.Tab tab) {
                    pager.setCurrentItem(tab.getPosition());
                }

                @Override
                public void onTabUnselected(TabLayout.Tab tab) {
                    int pos = tab.getPosition();
                }

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

                }
            });
        }
        tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(pager));
        return root;
    }
}



public class ViewPagerAdapter extends FragmentPagerAdapter  {


    ArrayList<ConnectedBluetoothDevice> devicesList;
    ArrayList<DataViewFragment> dataViewFragments;

    public ViewPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    /**
     * Initializes the adaptor with the device list and the list of data fragments.
     * @param devicesList List of devices to be displayed in their own data fragment.
     */
    public void setDevicesList(ArrayList<ConnectedBluetoothDevice> devicesList) {
        this.devicesList = devicesList;
        dataViewFragments = new ArrayList<>();
        for (int i = 0; i < devicesList.size(); i++) {
            dataViewFragments.add(new DataViewFragment(devicesList.get(i)));
        }
    }

    /**
     * GetItem
     * @param position position of item in the viewPager list to be returned
     * @return fragment to view
     */
    @NonNull
    public Fragment getItem(int position) {
        if (dataViewFragments != null && position < dataViewFragments.size()) {
            return dataViewFragments.get(position);
        } else {
            return new DataViewFragment(null);
        }
    }

    @Override
    public int getCount() {
        return devicesList.size();
    }

    /**
     * Updates the tabs in tabLayout while swiping pages
     * @param position of the viewPage
     * @return title of the tab
     */
    public CharSequence getPageTitle(int position) {
        super.getPageTitle(position);
        return devicesList.get(position).getName();
    }

    public void clear() {
        dataViewFragments.clear();
    }
}

Some notes:一些注意事项:

  • I'm instructed to fix this bug in ViewPager and FragmentPagerAdapter, so please don't recommend me solutions in ViewPager2 and FragmentStatePagerAdapter:)我被指示在 ViewPager 和 FragmentPagerAdapter 中修复此错误,所以请不要向我推荐 ViewPager2 和 FragmentStatePagerAdapter 中的解决方案:)
  • I heard that setOffscreenPageLimit(0);我听说setOffscreenPageLimit(0); isn't the best practice so I want to avoid that situation (especially since I only need to pause the fragment but not destroy it)不是最佳实践,所以我想避免这种情况(特别是因为我只需要暂停片段而不破坏它)

This depends on the version of ViewPager you are using as it was added later.这取决于您使用的ViewPager版本,因为它是稍后添加的。

Your are using a deprecated constructor您正在使用已弃用的构造函数

So as long as your using a recent version of Viewpager you should use the non deprecated constructor:-因此,只要您使用最新版本的Viewpager ,您就应该使用不推荐使用的构造函数:-

public FragmentPagerAdapter(
    @NonNull FragmentManager fm,
    @FragmentPagerAdapter.Behavior int behavior
)

This constructor with the behaviour BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT构造函数具有行为BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT

then only the current Fragment is in the RESUMED state.那么只有当前片段在 RESUMED state 中。 All other fragments are capped at STARTED所有其他片段的上限为 STARTED

To get to the STARTED lifecycle state from RESUMED onPause is called.为了从RESUMED onPause进入STARTED生命周期 state 被调用。

so change所以改变

public ViewPagerAdapter(FragmentManager fm) {
        super(fm);
    }

to

public ViewPagerAdapter(FragmentManager fm) {
            super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
        }

This method is used to for calling functions to run only when the specified tab is selected.此方法用于仅在选择指定选项卡时调用函数才能运行。

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

    if (isVisibleToUser) {
      // add your tab functions here
    } else {
        // do nothing
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何从不同的ViewPager片段访问单个活动按钮?当前选中了哪个标签 - how to access single activity button from different ViewPager Fragment?which tab is currently selected 所选标签未传递到TabLayout中的片段 - Selected tab not being passed through to fragment in tablayout 从第二个Fragment的recyclerView中选择项目时如何切换到第一个Fragment? 两个片段都在带有 viewPager2 的 tablayout 中 - How to switch to the first fragment when selecting an item from the recyclerView of second Fragment? Both fragments are in tablayout with viewPager2 如何在ViewPager中加载片段时才选择它 - how load fragment in ViewPager only when its selected 如何在 TabLayout 中获取当前选定的选项卡索引? - How to get current selected tab index in TabLayout? 如何使用TabLayout在ViewPager中的Google Maps Fragment中获取当前位置 - How to get current location within a Google Maps Fragment in a ViewPager with TabLayout 如何在 ViewPager 和 TabLayout 中多次使用相同的 Fragment 类? - How to use same Fragment class multiple times in a ViewPager and TabLayout? 选项卡已选择计数器的TabLayout - TabLayout with Tab selected counter 在viewpager中选择时更改片段尺寸 - Change fragment dimensions when selected in viewpager 如何在两个不同的 Fragment (TabLayout) 中设置两个不同的 fonts - How to set two different fonts in two different Fragment (TabLayout)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM