3

我正在构建一个显示不同片段的应用程序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);
}

如您所见,我tempTab.getTabId()在这一行中将 String ( ) 传递给片段:

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

在片段本身中,我这样做是为了初始化它:

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

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

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

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

有人可以向我解释如何做到这一点吗?如何获取当前可见的片段实例,以便将 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;
        }
    }   
}

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

在其中,我有一个ListViewPager. 该列表的初始化如下:

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

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

我仍然检查这个选项。

4

4 回答 4

6

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

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

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在接口初始化之前调用你的接口。

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

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

就我而言,我用它来关闭ViewPager滑动功能。但是,我可以轻松地回调到 mapFragment 中的公共方法。我碰巧有 3 个片段ViewPager,我保留了参考。

更新

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

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

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

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

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

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

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并返回。

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

private Fragment x;

//in onCreate
x = new Fragment();

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

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

于 2013-06-25T13:45:28.587 回答
4

viewpager.getCurrentItem()您可以通过以下方式使用方法获取当前可见片段:

Fragment fr = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + mViewPager.getCurrentItem());
于 2014-05-20T10:36:53.300 回答
2

有点晚了,但对于那些正在寻找更简单的东西的人来说,现在是 2021 年。

由于您的视图寻呼机需要一个适配器,而您的适配器需要一个片段管理器,所以只需像这样使用 FragmentManager(Kotlin)

supportFragmentManager.fragments.first { it.isVisible && it.isAdded }

只是提醒一下,使用这种方式你binding.viewPager.offscreenPageLimit不能> 0

或者您可以currentItem像这样使用来自 ViewPager 的;

supportFragmentManager.fragments[viewPager.currentItem]
于 2021-05-22T18:35:16.267 回答
0

截至 2020 年,我在 Kotlin 中的做法:

在片段类中,我添加了一个公共变量:

var fragmentNo = 0

fragmentNo变量通过适配器填充如下getItem(注fragment.fragmentNo = pos)特别是:

    private inner class ViewPagerAdapter(fragmentManager: FragmentManager)
        : FragmentStatePagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {

        override fun getCount(): Int = list.size
        var position = 0
        lateinit var fragment: ExerciseFragment

        override fun getItem(pos: Int): Fragment {
            fragment = ExerciseFragment()
            position = pos
            val bundle = Bundle()
            bundle.putSerializable(Constants.WORD_ID, list[position])
            fragment.arguments = bundle
            fragment.fragmentNo = pos
            return fragment
        }

    }

之后,我在 viewpager 之外的按钮点击器中使用可见片段,如下所示:

btShowAnswer.setOnClickListener {
            Logger.print(this, "Show Answer Button clicked")

            val fr: ExerciseFragment? = supportFragmentManager.fragments.find {
                it is ExerciseFragment && it.fragmentNo == viewPager.currentItem
            } as? ExerciseFragment

            fr?.showAnswer()

        }

下面的行特别找到所需的片段:

val fr: ExerciseFragment? = supportFragmentManager.fragments.find {
                it is ExerciseFragment && it.fragmentNo == viewPager.currentItem
            } as? ExerciseFragment
于 2020-04-01T10:20:30.647 回答