用Fragment替换ViewPager - 然后导航回来

Tim*_*eed 30 android android-fragments android-viewpager fragmentpageradapter

我有一个活动,最初主持一个ViewPager,连接到FragmentPagerAdapter.

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

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

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

很明显ViewPager没有被添加到backstack中(这并不令人惊讶,因为它本身不是一个片段).但是我希望默认行为是背压将我带回到那个活动的初始阶段.查看(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();

    }
Run Code Online (Sandbox Code Playgroud)

PagerAdapter:

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";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

main 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>
Run Code Online (Sandbox Code Playgroud)

Fel*_*ima 37

很长一段时间我也遇到了同样的问题.解决方案变得非常简单,并且您不需要任何具有ViewPager可见性的黑客攻击.我在其他与SO相关的问题中进行了描述:在popBackStack之后,ViewPager中的片段未恢复

但是,为简单起见,您只需在ViewPager适配器中使用getChildFragmentManager(),而不是getSupportFragmentManager().所以,而不是这个:

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

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

    /** Setting the pagerAdapter to the pager object */
    mViewPager.setAdapter(pagerAdapter);
Run Code Online (Sandbox Code Playgroud)

你做这个:

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

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

    /** Setting the pagerAdapter to the pager object */
    mViewPager.setAdapter(pagerAdapter);
Run Code Online (Sandbox Code Playgroud)

  • 如果ViewPager托管在Fragment中,则getChildFragmentManager()很好,但如果ViewPager托管在FragmentActivity中,则不行. (9认同)

Men*_*rve 9

更新:
这不是"Android方式",它会导致列表视图的用户体验不佳.而是创建一个新活动.

对于寻找这个问题的简单解决方案的人,我只想总结一下我所做的.

我的架构:

  • FragmentActivity中的ViewPager(ActionBarActivity实际上是ActionBar支持.但ActionBarActivity实现了FragmentActivity).

  • 2个标签:

    • FragmentContainer1扩展了Fragment.
    • FragmentContainer2扩展了Fragment.

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

FragmentToShow fragment = new FragmentToShow();

getChildFragmentManager()
        .beginTransaction()
        .add(R.id.container, fragment)
        .commit();
Run Code Online (Sandbox Code Playgroud)

我们不希望将第一个片段添加到片段容器的backstack中,因为如果我们按下后退按钮,我们不想显示片段容器.

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

Fragment itemFragment = new ItemFragment();

getFragmentManager()
        .beginTransaction()
        .replace(R.id.container, itemFragment)
        .addToBackStack(null)
        .commit();
Run Code Online (Sandbox Code Playgroud)

这里我们检索子片段管理器,然后将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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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


Tim*_*eed 3

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

当离开 viewPager 时,使用 Visiblity.GONE 将 viewPager 移出视图。将任何片段事务添加到后台堆栈。

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

fragmentManager.getBackStackEntryCount() == 0,backstack中没有碎片。

如果该陈述为真,则只需使用 Visibility.VISIBLE 将 viewPager 返回到视图中即可。