我有一个ViewPager,每次加载三个页面。如果我从第一页向右滑动到第二页然后到第三页,第一页(fragment)将进入onPause()
。然后,如果我向第二页滑动,第一页将回到onResume()
,即使页面1对用户仍不可见。所以我的问题是:如何在代码中区分第一页和第二页?例如,如果我必须在片段可见时运行一段代码,该如何做到?
我有一个ViewPager,每次加载三个页面。如果我从第一页向右滑动到第二页然后到第三页,第一页(fragment)将进入onPause()
。然后,如果我向第二页滑动,第一页将回到onResume()
,即使页面1对用户仍不可见。所以我的问题是:如何在代码中区分第一页和第二页?例如,如果我必须在片段可见时运行一段代码,该如何做到?
FragmentPagerAdapter会将除了当前显示的fragment以外的其他fragment保持在恢复状态。解决方法是实现一个自定义的OnPageChangeListener,并为fragment显示时创建一个新的方法。
1)创建LifecycleManager接口,这个接口将有两个方法,每个ViewPager的Fragment都将实现它。这些方法如下:
public interface FragmentLifecycle {
public void onPauseFragment();
public void onResumeFragment();
}
2) 让每个碎片实现接口Add,将implements语句添加到每个类声明中:
public class FragmentBlue extends Fragment implements FragmentLifecycle
public class FragmentGreen extends Fragment implements FragmentLifecycle
public class FragmentPink extends Fragment implements FragmentLifecycle
3)在每个片段中实现接口方法为了检查它是否按预期工作,我将仅记录方法调用并显示Toast:
@Override
public void onPauseFragment() {
Log.i(TAG, "onPauseFragment()");
Toast.makeText(getActivity(), "onPauseFragment():" + TAG, Toast.LENGTH_SHORT).show();
}
@Override
public void onResumeFragment() {
Log.i(TAG, "onResumeFragment()");
Toast.makeText(getActivity(), "onResumeFragment():" + TAG, Toast.LENGTH_SHORT).show();
}
4) 在ViewPager页面更改时调用接口方法 您可以在ViewPager上设置OnPageChangeListener,并在每次ViewPager显示另一页时获取回调:
pager.setOnPageChangeListener(pageChangeListener);
5)实现OnPageChangeListener来调用你的自定义生命周期方法。
监听器知道新的位置,并且可以借助PagerAdapter在新Fragment上调用接口方法。我可以在这里为新片段调用onResumeFragment(),对当前片段调用onPauseFragment()。
我还需要存储当前片段的位置(最初当前位置等于0),因为我不知道用户是从左向右滚动还是从右向左滚动。在代码中可以看到我的意思:
private OnPageChangeListener pageChangeListener = new OnPageChangeListener() {
int currentPosition = 0;
@Override
public void onPageSelected(int newPosition) {
FragmentLifecycle fragmentToShow = (FragmentLifecycle)pageAdapter.getItem(newPosition);
fragmentToShow.onResumeFragment();
FragmentLifecycle fragmentToHide = (FragmentLifecycle)pageAdapter.getItem(currentPosition);
fragmentToHide.onPauseFragment();
currentPosition = newPosition;
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) { }
public void onPageScrollStateChanged(int arg0) { }
};
我没有编写这段代码。完整的教程在这里:http://looksok.wordpress.com/2013/11/02/viewpager-with-detailed-fragment-lifecycle-onresumefragment-including-source-code/
getItem(pos)
方法返回新的 Fragment 实例,但我们需要将已缓存的片段添加到片段管理器。因此,您需要在新创建但未附加到Activity实例上的片段上调用 .onPauseFragment()
方法。请不要复制粘贴未经测试的代码。为什么它会被接受呢? - vigilancer如果你的Fragment扩展了android.support.v4.app.Fragment
你可以使用这个,它对我有效。
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (!isVisibleToUser) {
//do sth..
}
}
getActivity()
或getContext()
将返回null。我个人更喜欢onPageSelected()
方法的方式。 - Sira Lam使用pager.setOffscreenPageLimit(number)方法来设置您想在堆栈中保留多少个片段。
重写 setUserVisibleHint()
方法。此方法将在片段对用户可见时调用。
重写 setUserVisibleHint(),当片段对用户可见时将调用此函数。
解决您的问题:
public class FragmentVisibleHelper implements LifecycleObserver {
private static final String TAG = "VipVisibleHelper";
public interface IVisibleListener {
void onVisible();
void onInVisible();
}
boolean mIsVisibleToUser;
boolean mStarted = false;
volatile boolean mIsCalledVisible = false;
volatile boolean mIsCalledInvisible = false;
IVisibleListener mListener;
public void setListener(IVisibleListener mListener) {
this.mListener = mListener;
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
void onResume() {
Log.d(TAG, String.format("%-60s %s", this.toString(), "onResume() called:"));
if (mIsVisibleToUser) {
dispatchVisible();
}
}
private void dispatchVisible() {
Log.d(TAG, String.format("%-60s %s", this.toString(), "dispatchVisible() called mIsCalledVisible = [" + mIsCalledVisible + "] mIsCalledInvisible = [" + mIsCalledInvisible + "] "));
if (!mIsCalledVisible) {
mIsCalledVisible = true;
mIsCalledInvisible = false;
if (Profile.LOG) {
Log.d(TAG, String.format("%-60s %s", this.toString(), "dispatchVisible() called onVisible"));
}
if (mListener != null) {
mListener.onVisible();
}
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
void onPause() {
Log.d(TAG, String.format("%-60s %s", this.toString(), "onPause() called:"));
if (mIsVisibleToUser) {
dispatchInvisible();
}
}
private void dispatchInvisible() {
Log.d(TAG, String.format("%-60s %s", this.toString(), "dispatchInvisible() called mIsCalledVisible = [" + mIsCalledVisible + "] mIsCalledInvisible = [" + mIsCalledInvisible + "] "));
if (!mIsCalledInvisible) {
mIsCalledInvisible = true;
mIsCalledVisible = false;
if (Profile.LOG) {
Log.d(TAG, String.format("%-60s %s", this.toString(), "dispatchInvisible() called onInVisible"));
}
if (mListener != null) {
mListener.onInVisible();
}
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
void onStart() {
Log.d(TAG, String.format("%-60s %s", this.toString(), "onStart() called"));
mStarted = true;
if (mIsVisibleToUser) {
dispatchVisible();
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void onStop() {
Log.d(TAG, String.format("%-60s %s", this.toString(), "onStop() called"));
if (mIsVisibleToUser) {
dispatchInvisible();
}
mStarted = false;
}
public void setUserVisibleHint(boolean isVisibleToUser) {
Log.d(TAG, String.format("%-60s %s", this.toString(), "setUserVisibleHint() called with: isVisibleToUser = [" + isVisibleToUser + "]:"));
mIsVisibleToUser = isVisibleToUser;
if (mStarted) { // fragment have created
if (mIsVisibleToUser) {
dispatchVisible();
} else {
dispatchInvisible();
}
}
}
public boolean isVisibleToUser() {
return mIsVisibleToUser;
}
}
在分页适配器中,您可以放置此方法。
public Object instantiateItem(@NonNull ViewGroup container, int position) {
Fragment fragment = fragments.get(position);
if (fragment == null) {
fragment = (Fragment) super.instantiateItem(container, position);
fragments.put(position, fragment);
}
return fragment;
}
public Fragment getFragment(int position) {
return fragments.get(position);
}
然后在页面更改监听器中,您可以获取当前片段并在片段内运行您的方法。
currentFragment = adapter.getFragment(viewPager.getCurrentItem());
((DetailNewsFragment)currentFragment).runYourMethod();
特别提示:不要使用adapter.getItem(position),因为它会返回一个新的片段实例。
在片段之间滑动时,片段的生命周期方法不会被调用。您可以使用 ViewPager.SimpleOnPageChangeListener
来解决这个问题。下面是一个示例代码(Kotlin)。
// other code
mViewPager.addOnPageChangeListener(object: ViewPager.SimpleOnPageChangeListener() {
override fun onPageSelected(position: Int) {
val oldPosition = mViewPager.currentItem
val oldFragment = mViewPager.adapter?.instantiateItem(mViewPager, oldPosition)
oldFragment.onPauseStuff() // Hint: do as here call onPause
val newFragment = mViewPager.adapter?.instantiateItem(mViewPager, position)
newFragment.onResumeStuff() // Hint: do as here call onResume
}
// other code