问题:ViewPager中的Fragment onResume()在片段实际可见之前被激发。

例如,我有2个带有ViewPager和FragmentPagerAdapter的片段。第二个片段仅对授权用户可用,我需要在片段可见时要求用户登录(使用警告对话框)。

但是,当第一个片段可见时,ViewPager创建第二个片段,以便缓存第二个碎片,并在用户开始滑动时使其可见。

因此,onResume()事件在第二个片段可见之前很久就被激发了。这就是为什么我试图找到一个事件,当第二个片段变得可见时,该事件会触发,以便在适当的时候显示对话框。

如何做到这一点?


当前回答

为此重写Fragment.onHiddenChanged()。

公共void onHiddenChanged(布尔隐藏)当片段的隐藏状态(由isHidden()返回)更改时调用。碎片开始时并不隐藏;每当片段从中改变状态时,都会调用此函数。参数hidden-boolean:如果片段现在隐藏,则为True,如果不可见,则为false。

其他回答

我重写了关联的FragmentStatePagerAdapter的Count方法,并让它返回总计数减去要隐藏的页数:

 public class MyAdapter : Android.Support.V13.App.FragmentStatePagerAdapter
 {   
     private List<Fragment> _fragments;

     public int TrimmedPages { get; set; }

     public MyAdapter(Android.App.FragmentManager fm) : base(fm) { }

     public MyAdapter(Android.App.FragmentManager fm, List<Android.App.Fragment> fragments) : base(fm)
     {
         _fragments = fragments;

         TrimmedPages = 0;
     }

     public override int Count
     {
         //get { return _fragments.Count; }
         get { return _fragments.Count - TrimmedPages; }
     }
 }

因此,如果最初有3个片段添加到ViewPager中,并且在满足某些条件之前只应显示前2个片段,则通过将TrimmerdPages设置为1来覆盖页面计数,并且它应只显示前两个页面。

这对结尾的页面很有用,但对开头或中间的页面没有帮助(尽管有很多方法)。

我在使用FragmentStatePagerAdapters和3个选项卡时遇到了同样的问题。每当单击第一个选项卡时,我必须显示一个Dilaog,并在单击其他选项卡时隐藏它。

单独重写setUserVisibleHint()无助于查找当前可见片段。

从第三个选项卡单击时----->第一个选项卡。第二个片段和第一个片段触发了两次。我将其与isResumed()方法结合使用。

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

    // Make sure that fragment is currently visible
    if (!isVisible && isResumed()) {
        // Call code when Fragment not visible
    } else if (isVisible && isResumed()) {
       // Call code when Fragment becomes visible.
    }

}
package com.example.com.ui.fragment;


import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.com.R;

public class SubscribeFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_subscribe, container, false);
        return view;
    }

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

        if (isVisibleToUser) {
            // called here
        }
    }

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

当视图寻呼机中的片段显示在屏幕上供用户查看时,我试图启动计时器时遇到了这个问题。

计时器总是在用户看到片段之前启动。这是因为片段中的onResume()方法在我们看到片段之前被调用。

我的解决方案是检查onResume()方法。当片段8是视图页面的当前片段时,我想调用某个方法“foo()”。

@Override
public void onResume() {
    super.onResume();
    if(viewPager.getCurrentItem() == 8){
        foo();
        //Your code here. Executed when fragment is seen by user.
    }
}

希望这有帮助。我经常看到这个问题。这似乎是我见过的最简单的解决方案。其他很多都与较低的API等不兼容。

只有这对我有用!!而setUserVisibleHint(…)现在已被弃用(我在末尾附上了文档),这意味着大多数其他答案已被弃用;-)

public class FragmentFirewall extends Fragment {
    /**
     * Required cause "setMenuVisibility(...)" is not guaranteed to be
     * called after "onResume()" and/or "onCreateView(...)" method.
     */
    protected void didVisibilityChange() {
        Activity activity = getActivity();
        if (isResumed() && isMenuVisible()) {
            // Once resumed and menu is visible, at last
            // our Fragment is really visible to user.
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        didVisibilityChange();
    }

    @Override
    public void setMenuVisibility(boolean visible) {
        super.setMenuVisibility(visible);
        didVisibilityChange();
    }
}

已测试并与NaviagationDrawer一起使用,TheisMenuVisible()将始终返回true(onResume()似乎足够了,但我们也希望支持ViewPager)。

setUserVisibleHint已弃用。如果重写此方法,则传入true时实现的行为应移动到Fragment.onResume(),传入false时实现的操作应移动到Fragment.onPause()。