31

我有一个活动,它最初托管一个 ViewPager,连接到一个 FragmentPagerAdapter。

当用户单击 ViewPager 的子片段中的项目时,我正在使用 FragmentTransaction 用我想要导航到的新片段替换空容器视图。

如果我在事务上使用 addToBackStack(),提交事务然后返回,我不会返回到 ViewPager 的视图(初始布局)。

如果我不在事务上使用 addToBackStack(),提交事务然后返回,应用程序退出。

似乎很明显 ViewPager 没有添加到后台堆栈(这并不奇怪,因为它本身不是一个片段)。但我希望默认行为是后台按下将我带回最初的活动查看(ViewPager)。

根据我所阅读的内容,似乎可能是因为正在发生片段事务,ViewPager 或 PagerAdapter 失去了应该显示哪个片段的跟踪。

我真的对此感到困惑,但我最终创建了一大堆覆盖 onBackPress 并显示和隐藏 viewpager 视图的代码。我会认为有一种更简单的方法可以使用默认行为来执行适当的导航。

tl;博士

A 是一个 Viewpager 托管片段。B是一个新的片段。

当我用 B 替换 A,然后按返回时,我希望导航回 A,但这并没有发生。

任何建议将不胜感激。

代码:

主要活动:

  @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);

        headingLayout = (RelativeLayout) findViewById(R.id.headingLayout);
        headingLayout.setVisibility(View.GONE);

        // Set up the ViewPager, attaching the adapter and setting up a listener
        // for when the
        // user swipes between sections.
        mViewPager = (ViewPager) findViewById(R.id.pager);

        mViewPager.setPageMargin(8);

        /** Getting fragment manager */
        FragmentManager fm = getSupportFragmentManager();

        /** Instantiating FragmentPagerAdapter */
        MyFragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(fm);

        /** Setting the pagerAdapter to the pager object */
        mViewPager.setAdapter(pagerAdapter);
.
.
.
}

    public void onListItemClicked(Fragment fragment) {
        fromPlayer = false;
        InitiateTransaction(fragment, true);

    }


    public void InitiateTransaction(Fragment fragment, boolean addToBackStack) {

        invalidateOptionsMenu();

        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();

        ft.replace(R.id.fragmentContainer, fragment).addToBackStack(null)
                .commit();

    }

寻呼机适配器:

package another.music.player;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import another.music.player.fragments.AlbumListFragment;
import another.music.player.fragments.ArtistListFragment;
import another.music.player.fragments.SongListFragment;

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {

    final int PAGE_COUNT = 3;

    /** Constructor of the class */
    public MyFragmentPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    /** This method will be invoked when a page is requested to create */
    @Override
    public Fragment getItem(int i) {
        switch (i) {
        case 0:
            ArtistListFragment artistListFragment = new ArtistListFragment();
            Bundle artistData = new Bundle();
            artistData.putInt("current_page", i + 1);
            artistListFragment.setArguments(artistData);
            return artistListFragment;

        case 1:
            AlbumListFragment albumListFragment = new AlbumListFragment();
            Bundle albumData = new Bundle();
            albumData.putInt("current_page", i + 1);
            albumData.putBoolean("showHeader", false);
            albumListFragment.setArguments(albumData);
            return albumListFragment;

        default:

            SongListFragment songListFragment = new SongListFragment();
            Bundle songData = new Bundle();
            songData.putInt("current_page", i + 1);
            songListFragment.setArguments(songData);
            return songListFragment;
        }
    }

    /** Returns the number of pages */
    @Override
    public int getCount() {
        return PAGE_COUNT;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        switch (position) {
        case 0:
            return "Artists";

        case 1:
            return "Albums";

        default:
            return "Songs";
        }
    }
}

主 xml(包含 fragmentContainer 和 ViewPager):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/app_background_ics" >

    <RelativeLayout
        android:id="@+id/headingLayout"
        android:layout_width="match_parent"
        android:layout_height="56dp" >
    </RelativeLayout>

    <FrameLayout
        android:id="@+id/fragmentContainer"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_below="@+id/headingLayout" />

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >

        <android.support.v4.view.PagerTabStrip
            android:id="@+id/pager_title_strip"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#33b5e5"
            android:paddingBottom="4dp"
            android:paddingTop="4dp"
            android:textColor="#fff" />
    </android.support.v4.view.ViewPager>

</RelativeLayout>
4

5 回答 5

43

I also had this very same problem for a long time. The solution turns out to be very simple, and you don't need any hacks with the ViewPager Visibility. I is described in this other SO related question: Fragment in ViewPager not restored after popBackStack

However, to make it simple, all you need is to use getChildFragmentManager() in your ViewPager adapter, instead of getSupportFragmentManager(). So, instead of this:

    /** Getting fragment manager */
    FragmentManager fm = getSupportFragmentManager();

    /** Instantiating FragmentPagerAdapter */
    MyFragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(fm);

    /** Setting the pagerAdapter to the pager object */
    mViewPager.setAdapter(pagerAdapter);

You do this:

    /** Getting fragment manager */
    FragmentManager fm = getChildFragmentManager();

    /** Instantiating FragmentPagerAdapter */
    MyFragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(fm);

    /** Setting the pagerAdapter to the pager object */
    mViewPager.setAdapter(pagerAdapter);
于 2013-06-27T18:54:05.447 回答
9

更新:
这不是“Android 方式”,它会导致列表视图的用户体验不佳。相反,创建一个新活动。

对于寻找解决此问题的简单方法的人,我将总结一下我所做的。

我的架构:

  • FragmentActivity 中的 ViewPager(实际上是 ActionBarActivity,用于 ActionBar 支持。但 ActionBarActivity 实现了 FragmentActivity)。

  • 2 个标签:

    • 扩展 Fragment 的 FragmentContainer1。
    • 扩展 Fragment 的 FragmentContainer2。

对于每个 FragmentContainer,我们调用 getChildFragmentManager,例如在 onCreate 方法中,并添加我们想要在这个容器中显示的片段:

FragmentToShow fragment = new FragmentToShow();

getChildFragmentManager()
        .beginTransaction()
        .add(R.id.container, fragment)
        .commit();

我们不希望我们的第一个片段被添加到片段容器的后台堆栈中,因为我们不想在按下后退按钮时显示片段容器。

然后,如果我们想用我们的 FragmentToShow 类中的另一个片段替换 FragmentToShow(比如使用 listView):

Fragment itemFragment = new ItemFragment();

getFragmentManager()
        .beginTransaction()
        .replace(R.id.container, itemFragment)
        .addToBackStack(null)
        .commit();

在这里,我们检索子片段管理器,并将 itemFragment 添加到后堆栈。

所以现在我们想要在按下后退按钮时返回到 listView(FragmentToShow 实例)。我们的活动(FragmentActivity)是唯一知道后退按钮的活动,因此我们必须在此活动中覆盖 onBackPressed() 方法:

@Override
public void onBackPressed() {

    // We retrieve the fragment manager of the activity
    FragmentManager frgmtManager = getSupportFragmentManager();

    // We retrieve the fragment container showed right now
    // The viewpager assigns tags to fragment automatically like this
    // mPager is our ViewPager instance
    Fragment fragment = frgmtManager.findFragmentByTag("android:switcher:" + mPager.getId() + ":" + mPager.getCurrentItem());

    // And thanks to the fragment container, we retrieve its child fragment manager
    // holding our fragment in the back stack
    FragmentManager childFragmentManager = fragment.getChildFragmentManager();

    // And here we go, if the back stack is empty, we let the back button doing its job
    // Otherwise, we show the last entry in the back stack (our FragmentToShow) 
    if(childFragmentManager.getBackStackEntryCount() == 0){
        super.onBackPressed();
    } else {
        childFragmentManager.popBackStack();
    }
}

由于我们在活动中调用 getSupportFragmentManager,所以我们可以在子片段中调用 getFragmentManager。这将返回一个支持 FragmentManager 实例。

就是这样!我不是专家,所以如果您有任何建议或意见,请随意。

于 2013-08-02T15:04:20.057 回答
3

我发现实现这一目标的唯一方法是执行以下操作:

离开 viewPager 时,使用 Visiblity.GONE 将 viewPager 发送到视野之外。将任何片段事务添加到后台堆栈。

返回 viewPager 屏幕时(通过后按),覆盖 onBackPressed。您可以查看后台堆栈中有多少个片段。如果 viewPager 是片段事务发生之前的第一个视图,那么您可以检查片段回栈条目计数是否为 0。

fragmentManager.getBackStackEntryCount() == 0,回栈中没有分片。

如果该陈述为真,那么只需使用 Visibility.VISIBLE 将 viewPager 带回视图。

于 2012-09-24T03:51:04.193 回答
0

如果您使用的是可以 start的ViewPager包含,那么在回击或从所述位置向上导航时,您将如何正确导航回 中的位置(假设您为您的 声明了向上导航)。FragmentsActivitiesViewPagerActivityActivities

首先,您需要将 的当前位置ViewPager作为 Extra传递Intent给新的Activity.

然后你将把这个位置传回给父母Activity这样做:

Intent upIntent = NavUtils.getParentActivityIntent(this);
upIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
upIntent.putExtra(FeedPagerActivity.EXTRA_POSITION, position);
NavUtils.navigateUpTo(this, upIntent);

将该代码放入

onOptionsItemSelected(菜单项项)

于 2014-05-28T16:47:34.057 回答
0

我想我有一个非常相似的问题。

似乎FragmentManagers 的行为有点分层。我解决这个问题的方法是使用活动中的“主”FragmentManager,它承载容器和 ViewPager,而不是可以从 ViewPager 内的片段中检索的那个。

为此,我使用了:

this.getActivity().getSupportFragmentManager()

其中this是 Fragment 的一个实例。

现在,如果我从 ViewPager 中的一个项目导航到具有“替换”事务的其他片段,返回后我可以看到 ViewPager 处于我离开的状态。

更完整的代码示例如下所示:

FragmentManager fragmentManager =  MyCurrentFragment.this.getActivity().getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();

transaction.replace(R.id.container, newFragment);
transaction.addToBackStack(null);

transaction.commit();
于 2014-11-05T08:42:18.490 回答