56

ViewPager与片段一起使用时,在选项卡之间移动时不会调用我们的onPause,onResume方法。当我们变得可见或被隐藏时,有什么方法可以在片段中找出?

不幸的是,我在 , 中有逻辑onResumeonPause例如向位置服务注册,在切换选项卡时永远不会停止,因为onPause在退出整个应用程序之前永远不会被调用。

4

10 回答 10

18

ViewPager 带有OnPageChangeListener界面。通过为先前和当前显示的页面设置一些标志,您可以模拟这种行为。

于 2012-06-02T07:41:44.187 回答
10

考虑到以前的解决方案不是很清楚,以下是我如何解决它,感谢 Phix 的提示:

在 OnPageChange() 回调中:

    Fragment old_fragment = getActiveFragment(old_position);
    Fragment new_fragment = getActiveFragment(new_position);
    old_f.setUserVisibleHint(false);
    old_f.onPause();
    new_f.setUserVisibleHint(true);
    new_f.onResume();

然后在 onResume() 中:

    if (getUserVisibleHint())
        /* resume code */

在 onPause() 中:

    if (!getUserVisibleHint())
        /* pause code */

这是 getActiveFragment 代码,避免搜索它:

    return fragmentManager.findFragmentByTag("android:switcher:" + viewPagerId + ":" + position);

注意:Fragment 有一个 isVisible() 方法,但它似乎不是很一致,因此使用了 UserVisibleHint。

编辑:用私有标志替换 UserVisibleHint 。工作得更好!

于 2012-12-26T02:48:38.057 回答
8

如果您使用的是 Android 支持库 (rev 11),您可以使用getUserVisibleHint或覆盖setUserVisibleHint()来捕获可见和隐藏的更改。看这个帖子

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) {
        // do something when visible.
    }
}
于 2018-01-24T03:42:39.050 回答
5

当前版本的ViewPager库允许开箱即用地启用所需的行为,只需将FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT其作为第二个参数传递给FragmentPagerAdapter

还可以考虑使用ViewPager2来替换ViewPager. ViewPager2调用onPause()onResume()默认情况下,不需要配置。

有关更多详细信息,请参阅此答案

于 2020-06-11T13:43:16.323 回答
4

解决方案1:

SparseArray在您ViewPagers的 ' 适配器中定义 a ,如下所示。在这个数组中,我们将保存片段的实例。

SparseArray<Fragment> registeredFragments = new SparseArray<>();

还有Override你的适配器instantiateItem方法。

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Fragment fragment = (Fragment) super.instantiateItem(container, position);
    registeredFragments.put(position, fragment);
    return fragment;
}

还有Override destroyItem你的方法ViewPagers

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    registeredFragments.remove(position);
    super.destroyItem(container, position, object);
}

并定义一个新方法来获取您的ViewPager Fragments实例。

public Fragment getRegisteredFragment(int position) {
    return registeredFragments.get(position);
} 

现在您可以使用ViewPager's OnPageChangeListener. 这是一个有关如何实现 viewpager 的示例onPageChangeListener

定义一个整数来保持当前位置:

int currentPos;

yourViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                // Empty method
            }

            @Override
            public void onPageSelected(int position) {
                  // This is paused fragment.
                  final Fragment pausedFragment = yourAdapter.getRegisteredFragment(currentPos);

                  // update current position value
                  currentPos = position;

                  // This is resumed fragment
                  final Fragment resumedFragment = yourAdapter.getRegisteredFragment(currentPos);
            }

            @Override
            public void onPageScrollStateChanged(int state) {
                // Empty method
            }
        });

最后为了恢复实例状态更新您当前的位置以保持更新用户离开的位置ViewPager

currentPos = yourViewPager.getCurrentItem();

解决方案2:

对于另一种解决方案,您可以找到您ViewPager Fragments的 by Tag。您可以使用以下命令生成标签:

@NonNull
public static String generateViewPagerFragmentTag(int viewPagerId, int position) {
        final StringBuilder tagBuilder = new StringBuilder();
        tagBuilder.append("android:switcher:");
        tagBuilder.append(viewPagerId);
        tagBuilder.append(":");
        tagBuilder.append(position);
        return tagBuilder.toString();
    }

并找到你的Fragment

final Fragment yourFragment = getSupportFragmentManager().findFragmentByTag(generateViewPagerFragmentTag(R.id.your_viewpager, currentPos));

编辑:

几年前,当我在寻找获取当前项目的解决方案时,我在s 中ViewPager尝试过,发现它不可靠。我不确定它现在是否可靠,但我仍然避免使用。userVisibleHintFragment

于 2015-05-07T13:43:26.877 回答
2

您可以使用以下方法Fragment

public void setUserVisibleHint(boolean isVisibleToUser){

}

isVisibleToUser == true,显示片段

于 2017-04-06T10:43:15.230 回答
1

经过一番研究,我找到了完美的解决方案。

当你初始化你的适配器时,这样做: -

    import static androidx.fragment.app.FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT;

//(i am using androidx but if you have not yet migrated yet you can use appcompat)

    adapter = new FeedTabsPagerAdapter(getSupportFragmentManager(), BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);

添加此行后,您将完美地获得 onResume() 和 onPause 回调。如果我的代码解决了这个问题,请将其标记为正确的解决方案。干杯!

于 2019-10-18T15:16:24.547 回答
1

使用 Viewpager2 最新版本,它只会在您滚动到该片段时调用 onResume(),就像 Vp1 之前为 +1 下一个片段调用它一样。

于 2022-01-19T13:18:32.537 回答
0

聚会有点晚了,但是在我当前的应用程序中,我已将 Viewpager 的 OffScreenPageLimit 设置为 1,这意味着片段不会被缓存,并且每次视图更改时都会重新加载当前片段

https://developer.android.com/reference/android/support/v4/view/ViewPager.html#getOffscreenPageLimit()

于 2016-05-17T12:16:49.683 回答
0

为savepopulation的答案中的方法提供更多定义:

yourPager.setOnPageChangeListener(new GridViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int row, int column, float rowOffset, float columnOffset, int rowOffsetPixels, int columnOffsetPixels) {

        }

        @Override
        public void onPageSelected(int row, int column) {
            // When on page selected if position is not specific for you
            // you can find your fragment or you can switch position.
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });
于 2016-08-18T20:11:44.050 回答