如何在ViewPager中获取当前可见片段的实例:

Emi*_*Adz 2 android instance android-fragments android-viewpager

我正在构建一个显示不同片段的应用程序ViewPager.我将这些片段添加到ViewPager这样的:

 public void intialiseViewPager() 
 {
    List<Fragment> fragments = new Vector<Fragment>();
    numberOfTabs = application.currentReport.getODTabsList().size();
    for (int i = 0; i < numberOfTabs; i++)      
    {
        ODTab tempTab = application.currentReport.getODTabsList().get(i);
        if (tempTab.getTabType().equals(ODGrid.XML_GRID_ELEMENT))
        {
            GridFragment gridFragment = GridFragment.newInstance(tempTab.getTabId());
            fragments.add(gridFragment);
        }
        else  if (tempTab.getTabType().equals(ODChart.XML_CHART_ELEMENT))
        {
            NewChartFragment chartFragment = NewChartFragment.newInstance(tempTab.getTabId());
            fragments.add(chartFragment);
        }
    }
    Log.d(TAG, "Current report fragments set to adapter: "+fragments.toString());
    mPagerAdapter  = new ViewPagerAdapter(getSupportFragmentManager(), fragments);
    mViewPager = (ViewPager)findViewById(R.id.pager);
    mViewPager.setAdapter(mPagerAdapter);
    mViewPager.setOffscreenPageLimit(0);
    mViewPager.setOnPageChangeListener(this);
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我tempTab.getTabId()在此行中传递了一个String()片段:

GridFragment gridFragment = GridFragment.newInstance(tempTab.getTabId());
Run Code Online (Sandbox Code Playgroud)

在片段本身我这样做来初始化它:

public static final GridFragment newInstance(String tabId)
{
    GridFragment f = new GridFragment();
    Bundle bdl = new Bundle(2);
    bdl.putString(TAB_ID, tabId);
    f.setArguments(bdl);
    return f;
}

@Override
public void onCreate(Bundle savedInstanceState) 
{
    String tabId = getArguments().getString(TAB_ID);
    if (application.currentReport != null)
    {
        this.odTab = application.currentReport.getODTabByTabId(tabId);
    }
    else
    {
        startActivity(new Intent(getActivity(), LoginScrActivity.class));
    }
    super.onCreate(savedInstanceState);
}
Run Code Online (Sandbox Code Playgroud)

执行所有这些是为了不覆盖片段的默认空构造函数,因为我知道不建议这样做.

现在我需要获取odTab我放入此行中当前可见片段的对象的实例:

this.odTab = application.currentReport.getODTabByTabId(tabId);
Run Code Online (Sandbox Code Playgroud)

有人可以向我解释如何做到这一点?如何获取当前可见的片段实例,以便将odTab对象拉出来?

更新: 根据我在这里收到的建议,我已经将一个odTab对象实例添加到被调用的应用程序类中,currentVisibleTab我正在设置odTab的实例,如下所示:

@Override
public void setUserVisibleHint(boolean isVisibleToUser) 
{
    Log.d(TAG, "setUserVisibleHint invoked!");
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) 
    {
        if (odTab != null && getActivity() != null)
        {
            Log.d(TAG, "Currently visable tab: "+odTab.getTabTitle());
            application.currentVisibleTab = odTab;
        }
    }   
}
Run Code Online (Sandbox Code Playgroud)

UPDATE2: 这是我的ViewPagerAdapter:

public class ViewPagerAdapter extends FragmentPagerAdapter 
{
private List<Fragment> fragments;

/**
 * @param fm
 * @param fragments
 */
public ViewPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
    super(fm);
    this.fragments = fragments;
}

/* (non-Javadoc)
 * @see android.support.v4.app.FragmentPagerAdapter#getItem(int)
 */

@Override
public Fragment getItem(int position) {
    return this.fragments.get(position);
}

/* (non-Javadoc)
 * @see android.support.v4.view.PagerAdapter#getCount()
 */

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

@Override
public int getItemPosition(Object object) {
    return POSITION_NONE;
} 

public void removeAllFragments()
{
    this.fragments.clear();
}

public void addFragmentsListToAdapter(List<Fragment> fragments)
{
    this.fragments.addAll(fragments);
}

public List<Fragment> getFragments()
{
    return fragments;
}
}
Run Code Online (Sandbox Code Playgroud)

在其中我有一个List片段,由显示ViewPager.此列表初始化如下:

 List<Fragment> fragments = new Vector<Fragment>();
Run Code Online (Sandbox Code Playgroud)

我不明白的是我如何获得从该列表中触发接口方法的当前片段的引用.这不是一个相关的问题,但也许你知道答案:List和之间有什么区别Vector

我仍然检查这个选项.

Rar*_*arw 6

我发现当前可见片段的方式是使用setUserVisibleHint和接口返回ViewPager.此方法位于片段类中.覆盖它并使用界面回拨你的ViewPager.如果片段是可见的 - 即它返回true - 那么只需使用对片段的引用(从支持适配器的列表或作为实例变量存储的片段)来获取片段本身所需的任何内容.我已添加以下代码.

声明与您想要执行的任何操作相关的接口.在我的情况下,ViewPager当Google Map实例可见时,我使用它来禁用默认的x方向侦听器,以便滚动地图不会触发片段的更改.

public interface OnMapFragmentVisibleListener{
    public void mapVisible(boolean visible);
}
Run Code Online (Sandbox Code Playgroud)

在片段中:

@Override 
public void onAttach(Activity activity){ 
    super.onAttach(activity);
    try{
        mapFragmentVisibilityListener = (OnMapFragmentVisibleListener) activity;
        isAttached = true; //flag for whether this fragment is attached to pager
    } catch (ClassCastException e){
        throw new ClassCastException(activity.toString() + " must implement interface onAttach");
    }


@Override
public void setUserVisibleHint(boolean isVisibleToUser){
    if(isVisibleToUser && isAttached){ //if listener is called before fragment is attached will throw NPE
        mapFragmentVisibilityListener.mapVisible(true);
    }
}
Run Code Online (Sandbox Code Playgroud)

在我尝试这个之前不明显的一件事是增加了isAttached变量.我还覆盖了片段onAttach方法,并在调用后将其设置为true.否则,您的片段将对用户可见,并尝试ViewPager在界面初始化之前调用接口.

在我的ViewPager实现OnMapFragmentVisibleListener,然后添加所需的方法

    @Override
public void mapVisible(boolean visible) {
    if(visible)
    viewPager.allowSwipe(false); //turn off viewPager intercept touch if map visible
}
Run Code Online (Sandbox Code Playgroud)

在我的情况下,我用它来关闭ViewPager滑动功能.但是,我可以在mapFragment中轻松回调一个公共方法.我碰巧有3个片段ViewPager,我一直参考.

更新

要查找当前显示的片段,首先需要找出正在显示的片段.你可以通过多种方式实现这一目标.最简单的方法是使用您之前创建的接口将一些描述符传递回ViewPager/ FragmentActivity.

public interface OnFragmentVisibleListener{
    public void fragmentVisible(boolean true, String tag);
}
Run Code Online (Sandbox Code Playgroud)

您的设置问题是您正在使用一个Vector实际上是同步List来存储您的片段引用.因此,您之后无法找到片段的关键值.片段具有通过在片段事务中添加到片段活动期间创建的标记来标识的能力.但是,在ViewPager设置中,您不会单独添加片段,因此无法在事务期间添加标记.

我的解决方案一直是我回BasePagerAdapterHashMap我在其中存储由一个唯一的密钥识别的每一个片段.

 LinkedHashMap<String, Fragment> tabs = new LinkedHashMap<String, Fragment>();
 tabs.put("Frag1", fragment1);
 tabs.put("Frag2", fragment2);
 tabs.put("Frag3", fragment3);
Run Code Online (Sandbox Code Playgroud)

然后我在适配器中使用它:

private class BasePagerAdapter extends FragmentPagerAdapter{

    private LinkedHashMap<String, Fragment> tabs;

    public BasePagerAdapter(LinkedHashMap<String, Fragment> tabMap, FragmentManager fm)
    {
        super(fm);
        this.tabs = tabMap;
    }

     // other basic methods
Run Code Online (Sandbox Code Playgroud)

因为您的引用存储为键值,所以很容易找到您正在查找的片段,因为您只需按键HashMap和返回键即可.

如果您无法更改设置以远离Vector您需要(1)跟踪您添加的片段(假设片段未动态添加和删除),以便您可以通过索引或(2)获取保持对每个片段的单独引用.

private Fragment x;

//in onCreate
x = new Fragment();

//in interface
if(tag.equals("x"){
    x.doSomething();
}
Run Code Online (Sandbox Code Playgroud)

使这更容易的另一件事是我的碎片都是子类.例如,执行不同功能的每个片段都有自己的类.因为每个类只有一个实例,所以很容易找到,因为我没有任何重复项.如果您正在使用Fragment该类的所有通用成员,您只需要实现一些标记系统,使上述方法之一成为可能.