如何在 ViewPager 中获取当前可见片段的实例: [英] How to get the instance of the currently visible fragment in ViewPager:

查看:28
本文介绍了如何在 ViewPager 中获取当前可见片段的实例:的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm building an application that shows different fragments in a ViewPager. I add these fragments to the ViewPager like this:

 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);
}

如您所见,我在这一行中向片段传递了一个字符串 (tempTab.getTabId()):

As you can see I pass to the fragment a String (tempTab.getTabId()), in this line:

GridFragment gridFragment = GridFragment.newInstance(tempTab.getTabId());

在片段本身中,我这样做是为了对其进行初始化:

In the fragment itself I do this to initialize it:

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);
}

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

All this is performed in order to not override the default empty constructor of the fragment, as I understand that this is not recommended.

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

Now I need to get the instance of the odTab object that I put into the currently visible fragment in this line:

this.odTab = application.currentReport.getODTabByTabId(tabId);

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

Could someone please explain to me how this could be done? How do I get the currently visible fragment instance so I can pull the odTab object out of it?

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

UPDATE: With the suggestions I received here I have added an odTab object instance to the application class that is called currentVisibleTab and I'm setting the instance of the odTab like this:

@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;
        }
    }   
}

更新 2:这是我的 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;
}
}

其中我有一个 List 片段,由 ViewPager 显示.这个列表是这样初始化的:

In it I have a List of fragments that are shown by the ViewPager. This list is initialized like this:

 List<Fragment> fragments = new Vector<Fragment>();

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

What I don't understand is how I get a reference to the current fragment that triggered the interface method from this list. And this is not a related question but maybe you know the answer: What is the difference between List and Vector?

我仍然检查这个选项.

推荐答案

我找到当前可见片段的方法是使用 setUserVisibleHint 和返回 ViewPager.这个方法在 fragment 类.覆盖它并使用接口回调您的 ViewPager.如果片段是可见的 - 即它返回 true - 然后只需使用对片段的引用(来自支持适配器的列表或存储为实例变量的列表)即可从片段本身中获取所需的任何内容.我已经添加了下面的代码.

The way I've found the currently visible fragment is using setUserVisibleHint and an interface back to the ViewPager. This method is in the fragment class. Override it and use an interface to call back to your ViewPager. If the fragment is visible - i.e. it returns true - then just use a reference to your fragment (either from the list backing your adapter or one you stored as an instance variable) to get whatever you need out of the fragment itself. I've added the code below.

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

Declare an interface related to whatever you want to do. In my case I was using this to disable the ViewPager default x-direction listener when a Google Map instance was visible so that the scrolling of the map did not trigger the change of fragment.

public interface OnMapFragmentVisibleListener{
    public void mapVisible(boolean visible);
}

在片段中:

@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);
    }
}

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

One thing that was not obvious until I tried this out was the addition of the isAttached variable. I also override the fragments onAttach method and set this to true once it is called. Otherwise what happens is your fragment will be visible to the user and try to call the interface to your ViewPager before the interface is initialized.

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

In my ViewPager I just implement the OnMapFragmentVisibleListener and then add the required method

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

在我的例子中,我用它来关闭 ViewPager 滑动功能.但是,我可以轻松地回调到 mapFragment 中的公共方法.我的 ViewPager 中碰巧有 3 个片段,我保留了对这些片段的引用.

In my case I used it to turn off the ViewPager swipe function. However, I could have easily called back to a public method in my mapFragment. I happen to have 3 fragments in my ViewPagerthat I keep a reference to.

更新

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

To find the fragment that is currently displayed, you first need to find out which fragment is being displayed. You can do this a number of ways. The easiest is to pass some descriptor back to your ViewPager / FragmentActivity with the interface you created before.

public interface OnFragmentVisibleListener{
    public void fragmentVisible(boolean true, String tag);
}

您的设置问题在于您使用了一个 Vector,它实际上是一个同步的 List 来存储您的片段引用.因此,没有键值可用于稍后定位片段.当片段被添加到片段活动时,片段能够通过在片段事务期间创建的标签来识别.但是,在 ViewPager 设置中,您不会单独添加片段,因此无法在事务期间添加标签.

The problem with your setup is that you're using a Vector which is really a synchronized List to store your fragment references. As a result, there is no key value by which you can locate your fragments later. Fragments have the ability to be identified by a tag that is created during the fragment transaction when they are added to the fragment activity. However, in a ViewPager setup, you do not add the fragments individually and so can't add tags during the transaction.

我的解决方案是使用 HashMap 来支持我的 BasePagerAdapter,在其中存储由唯一键标识的每个片段.

My solution has been to back my BasePagerAdapter with a HashMap in which I store each fragment identified by a unique key.

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

然后我在适配器中使用这个:

Then I use this in the adapter:

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

因为您的引用存储到键值,所以很容易找到您要查找的片段,因为您只需从 HashMap 中按键搜索并返回.

Because your references are stored to key values, it's easy to find the fragment you're looking for because you can just search by key from the HashMap and return.

如果您无法更改设置以摆脱 Vector 您需要 (1) 跟踪您添加的片段以哪个顺序(假设片段不是动态添加和删除的)所以您可以通过索引获取它,或者 (2) 保留对每个片段的单独引用.

If you cannot change the setup to get away from the Vector you need to either (1) keep track of which fragment you add in which order (assuming fragments are not added and removed dynamically) so that you can get it by index or (2) keep separate references to each fragment.

private Fragment x;

//in onCreate
x = new Fragment();

//in interface
if(tag.equals("x"){
    x.doSomething();
}

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

Another thing that makes this easier is that my fragments are all sub-classed. E.g. each fragment that performs a different function has its own class. As there is only one instance of each class it is easy to find since I do not have any duplicates. If you're using all generic members of the Fragment class you just need to implement some system of tagging that makes one of the approaches above possible.

这篇关于如何在 ViewPager 中获取当前可见片段的实例:的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆