在ViewPager中用另一个Fragment替换Fragment

23

我正在使用ViewPager和FragmentPagerAdapter一起承载三个不同的片段

[Fragment1][Fragment2][Fragment3]

我的目标是,如果特定任务成功,成功替换Fragment1为一个全新的Fragment4。

当我使用...

FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.fragment1_layout_id, fragment4);
transaction.commit();

..片段被很好地替换了,Fragment4代替Fragment1展示。但是,一旦我滑动到Fragment3然后返回到Fragment4,Fragment1又会出现。

再说一遍,如果我使用..

FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.remove(fragment1);
transaction.commit();

当我移除Fragment1并返回时,会出现Fragment4。所以这种解决方案的问题在于,我找不到一种立即显示Fragment4且移除Fragment1的方法,即使我尝试了:

transaction.add(fragment4);
transaction.show(fragment4);

以下是我的FragmentPagerAdapter实现,没有任何事务管理

public static class PagerAdapter extends FragmentPagerAdapter {

    public PagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return VIEW_COUNT;
    }

    @Override
    public Fragment getItem(int position) {

        Fragment fragment = null;

        switch (position) {
        case 0:
            fragment = Fragment1.newInstance(context_);
            break;

        case 1:
            fragment = Fragment2.newInstance(context_);
            break;

        case 2:
            fragment = Fragment3.newInstance(context_);
            break;

        default:
            break;
        }

        return fragment;
    }
}

编辑。

看起来我在问题描述方面并不十分清楚。我决定移除我之前创建的所有混乱代码,并且尝试阐明我已经留下的部分(请参见上面加粗的文本)。

无论如何,这就是我一直在getItem()函数中尝试做的事情:

@Override
public Fragment getItem(int position) {

    Fragment fragment = null;

    switch (position) {
    case 0:

        if (!app.isUserLoggedIn) {
            if (loginFragment_ == null) {
                loginFragment_ = LoginFragment.newInstance(context_);
                transaction_ = fragmentManager_.beginTransaction();

                if (logoutFragment_ != null) {
                    transaction_.remove(logoutFragment_);
                    logoutFragment_ = null;
                }

                transaction_.add(loginFragment_, "login");
                transaction_.commit();
            }

            if (fragmentManager_.findFragmentByTag("login") == null)
                fragment = LoginFragment.newInstance(context_);
            else
                fragment = fragmentManager_.findFragmentByTag("login");

        } else {
            if (logoutFragment_ == null) {                      
                logoutFragment_ = LogoutFragment.newInstance(context_);
                transaction_ = fragmentManager_.beginTransaction();

                if (loginFragment_ != null) {
                    transaction_.remove(loginFragment_);
                    loginFragment_ = null;
                }

                transaction_.add(logoutFragment_, "logout");
                transaction_.commit();
            }

            if (fragmentManager_.findFragmentByTag("logout") == null)
                fragment = LogoutFragment.newInstance(context_);
            else
                fragment = fragmentManager_.findFragmentByTag("logout");
        }
        break;

    case 1:
        fragment = HomeFragment.newInstance(context_);
        break;

    case 2:
        fragment = RegisterFragment.newInstance(context_);
        break;

    default:
        break;
    }

    return fragment;
}

这段代码并没有实现我想要的功能,如果有人能指出我的错误并帮我指明正确的方向,我将非常感激!


我认为你应该在PagerAdapter中修改getItem。返回的片段必须是可见的。 - pawelzieba
@dziobas,那正是我一直试图在我的问题中描述的魔法所在,但却没有成功。 - velu
请查看我在类似问题上的答案,其中介绍了如何使用ViewPagerFragmentPagerAdapter插入/替换制表符。 - jfritz42
当我点击tab1时,会调用fragment2,但我不知道为什么会调用tab2?这是适配器错误吗? - Faisal Ashraf
5个回答

12

尝试使用FragmentStatePagerAdapter

http://android-developers.blogspot.com/2011_08_01_archive.html

因为你通过视图滑动(或调用getitem)来移除片段,所以不需要显式地自己删除它们。我一直遇到同样的问题,这对我有效。我尝试了你的代码并删除了“if (fragment!= null)”块,它可以正常工作。

能否展示一些代码吗?如果可以的话,我会非常感激的,因为我按照您的步骤操作,但是没有得到我想要的结果... - cesards

3
像Maurycy所说的那样,每当您想要告诉ViewPager已经替换了片段时,都需要调用mAdapter.notifyDataSetChanged()。但是,您还需要覆盖适配器中的getItemPosition()抽象函数,并在使用旧的、将要隐藏的片段作为参数调用时返回POSITION_NONE。否则,ViewPager将保留所有当前片段。
有关更多信息和示例代码,请参见此答案以及相关问题

0
嗨,我已经通过在我的FragmentPagerAdapter中使用List来处理各种Fragment来解决了这个问题,然后我的getItem就像这样...
    public void addScreen(String tag, Class<?> clss, Bundle args){
        if(clss!=null){
            TabInfo info = new TabInfo(tag, clss, args);
            screens.add(info);
        }
    }
@Override
    public Fragment getItem(int position) {
        TabInfo info = screens.get(position);
        return Fragment.instantiate(context, info.clss.getName(), info.args);
    }

我然后以编程方式删除/添加/重新排列列表项(片段),然后调用处理程序。
mAdapter.notifyDataSetChanged()

0

尝试将offScreenPageLimit设置为5(或根据您的用例)以避免重新加载片段,这样您替换的内容将保留,而不是在滑动时重新加载。

    mViewPager.setOffscreenPageLimit(5);

0

在某些情况下,你的getItem语句应该返回case 0fragment4吗?


是的,应该这样做,我一整天都在努力寻找正确的方法。我更新了我的问题并添加了我到目前为止的尝试方式。 - velu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接