ViewPager
和片段时,在选项卡之间移动时,我们的onPause
、onResume
方法不会被调用。有没有办法在片段中找出我们何时可见或隐藏?
很遗憾,我在onResume
、onPause
中有一些逻辑,比如注册位置服务,由于onPause
直到退出整个应用程序才会被调用,因此从一个选项卡切换到另一个选项卡时永远不会停止该逻辑。ViewPager
和片段时,在选项卡之间移动时,我们的onPause
、onResume
方法不会被调用。有没有办法在片段中找出我们何时可见或隐藏?
很遗憾,我在onResume
、onPause
中有一些逻辑,比如注册位置服务,由于onPause
直到退出整个应用程序才会被调用,因此从一个选项卡切换到另一个选项卡时永远不会停止该逻辑。ViewPager带有OnPageChangeListener
接口。通过为上一个和当前显示的页面设置一些标志,您可以模拟此行为。
考虑前面的解决方案不够清晰,这是我如何根据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);
NB: Fragment有一个isVisible()方法,但它似乎不是非常一致,因此使用UserVisibleHint。
编辑:将UserVisibleHint替换为私有标志。效果更好!
getUserVisibleHint
或覆盖setUserVisibleHint()
来捕获可见和隐藏的更改。请查看此帖子。@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
// do something when visible.
}
}
ViewPager
库的当前版本允许开箱即用地启用所需的行为,只需将FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
作为第二个参数传递给FragmentPagerAdapter即可。
另外考虑使用取代ViewPager
的ViewPager2。 ViewPager2
默认情况下调用onPause()
和onResume()
,无需配置。
有关详细信息,请参见此答案。
在您的ViewPagers
适配器中定义一个SparseArray
,如下所示。 在此数组中,我们将保存片段的实例。
SparseArray<Fragment> registeredFragments = new SparseArray<>();
覆盖您的适配器的instantiateItem
方法。
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
@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);
}
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:
另一种解决方案是通过Tag
查找您的ViewPager
Fragments
。您可以使用以下代码生成标签:
@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));
编辑:
几年前,当我在寻找获取 ViewPager
当前项目的解决方案时,我尝试了在 Fragment
中使用 userVisibleHint
,但发现它并不可靠。我不确定现在是否可靠,但我仍然避免使用。
Fragment
中使用以下方法。public void setUserVisibleHint(boolean isVisibleToUser){
}
isVisibleToUser == true
时,该片段被显示。经过一些研究,我找到了解决这个问题的完美方案。
当你初始化适配器时,要像这样做:
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);
为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) {
}
});
public void setUserVisibleHint(boolean isVisibleToUser)
方法,以了解“当前”选项卡视图是否正在显示。 - Gene Bo