更换ViewPager与碎片 - 然后导航返回碎片、ViewPager

2023-09-03 21:21:04 作者:回首释然

我已经得到了最初举办ViewPager活动,挂接到一个FragmentPagerAdapter。

当用户点击了ViewPager的子片段内的项目,我使用的是FragmentTransaction更换一个新的片段一个空的容器观点,我想浏览到。

如果我在事务中使用addToBackStack(),提交事务,然后再返回,我没有回到ViewPager的意见(初步设计)。

Android 4 Fragment,ViewPager

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

这似乎显而易见的是,ViewPager不会被添加到backstack(这并不奇怪,因为它本身并不是一个片段)。但我期望的默认行为将是后面preSS需要我回到了最初的活动视图(ViewPager)。

根据我读过

,看来也许是因为一个片段的交易正在进行中,ViewPager或PagerAdapter失去跟踪哪些片段要展出。

我真的很困惑这个问题,但我最终创造了code一个巨大的混乱覆盖onBack preSS和显示和隐藏viewpager意见。我会一直想有一个更简单的方法来使用默认的行为进行适当的导航。

TL;博士

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

当我为B代替A,然后preSS回来了,我希望能导航回到A,但是这并没有发生。

任何意见将是多少AP preciated。

code:

MainActivity:

  @覆盖
        公共无效的onCreate(包savedInstanceState){
            super.onCreate(savedInstanceState);
            的setContentView(R.layout.main);

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

        //设置的ViewPager,将适配器和设置侦听
        //为当
        //部分之间的用户刷卡。
        mViewPager =(ViewPager)findViewById(R.id.pager);

        mViewPager.setPageMargin(8);

        / **获取片段经理* /
        FragmentManager FM = getSupportFragmentManager();

        / **实例化FragmentPagerAdapter * /
        MyFragmentPagerAdapter pagerAdapter =新MyFragmentPagerAdapter(FM);

        / **的pagerAdapter设置到寻呼机对象* /
        mViewPager.setAdapter(pagerAdapter);
。
。
。
}

    公共无效onListItemClicked(片段片段){
        fromPlayer = FALSE;
        InitiateTransaction(片段,真实);

    }


    公共无效InitiateTransaction(片段片段,布尔addToBackStack){

        invalidateOptionsMenu();

        FragmentManager FM = getSupportFragmentManager();
        FragmentTransaction英尺= fm.beginTransaction();

        ft.replace(R.id.fragmentContainer,片段).addToBackStack(空)
                。承诺();

    }
 

PagerAdapter:

 包another.music.player;

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

公共类MyFragmentPagerAdapter扩展FragmentPagerAdapter {

    最终诠释PAGE_COUNT = 3;

    / **类的构造函数* /
    公共MyFragmentPagerAdapter(FragmentManager FM){
        超(FM);
    }

    / **当一个页面被请求创建*这个方法将被调用/
    @覆盖
    公共片段的getItem(int i)以{
        开关(ⅰ){
        情况下0:
            ArtistListFragment artistListFragment =新ArtistListFragment();
            捆绑artistData =新包();
            artistData.putInt(current_page,i + 1的);
            artistListFragment.setArguments(artistData);
            返回artistListFragment;

        情况1:
            AlbumListFragment albumListFragment =新AlbumListFragment();
            捆绑albumData =新包();
            albumData.putInt(current_page,i + 1的);
            albumData.putBoolean(showHeader,假);
            albumListFragment.setArguments(albumData);
            返回albumListFragment;

        默认:

            SongListFragment songListFragment =新SongListFragment();
            捆绑songData =新包();
            songData.putInt(current_page,i + 1的);
            songListFragment.setArguments(songData);
            返回songListFragment;
        }
    }

    / **返回的页面数量* /
    @覆盖
    公众诠释getCount将(){
        返回PAGE_COUNT;
    }

    @覆盖
    公共CharSequence的getPageTitle(INT位置){
        开关(位置){
        情况下0:
            返回艺术家;

        情况1:
            返回相册;

        默认:
            返回诗经;
        }
    }
}
 

主要XML(含fragmentContainer和放大器; ViewPager):

 < RelativeLayout的的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
    的xmlns:工具=htt​​p://schemas.android.com/tool​​s
    机器人:ID =@ + ID / main_layout
    机器人:layout_width =match_parent
    机器人:layout_height =match_parent
    机器人:背景=@可绘制/ app_background_ics>

    < RelativeLayout的
        机器人:ID =@ + ID / headingLayout
        机器人:layout_width =match_parent
        机器人:layout_height =56dp>
    < / RelativeLayout的>

    <的FrameLayout
        机器人:ID =@ + ID / fragmentContainer
        机器人:layout_width =FILL_PARENT
        机器人:layout_height =FILL_PARENT
        机器人:layout_below =@ + ID / headingLayout/>

    < android.support.v4.view.ViewPager
        机器人:ID =@ + ID /寻呼机
        机器人:layout_width =FILL_PARENT
        机器人:layout_height =FILL_PARENT>

        < android.support.v4.view.PagerTabStrip
            机器人:ID =@ + ID / pager_title_strip
            机器人:layout_width =match_parent
            机器人:layout_height =WRAP_CONTENT
            机器人:后台=#33b5e5
            机器人:paddingBottom会=4DP
            机器人:paddingTop =4DP
            机器人:文字颜色=#FFF/>
    < /android.support.v4.view.ViewPager>

< / RelativeLayout的>
 

解决方案

我也有很长一段时间这个非常相同的问题。该解决方案被证明是非常简单的,你不需要用ViewPager能见度任何黑客。我在此其他等相关的问题描述:Fragment在ViewPager popBackStack 后没有恢复

然而,为了使简单,您只需要使用getChildFragmentManager()在你的ViewPager适配器,而不是getSupportFragmentManager()。而不是这样呢,

  / **获取片段经理* /
    FragmentManager FM = getSupportFragmentManager();

    / **实例化FragmentPagerAdapter * /
    MyFragmentPagerAdapter pagerAdapter =新MyFragmentPagerAdapter(FM);

    / **的pagerAdapter设置到寻呼机对象* /
    mViewPager.setAdapter(pagerAdapter);
 

您做到这一点:

  / **获取片段经理* /
    FragmentManager FM = getChildFragmentManager();

    / **实例化FragmentPagerAdapter * /
    MyFragmentPagerAdapter pagerAdapter =新MyFragmentPagerAdapter(FM);

    / **的pagerAdapter设置到寻呼机对象* /
    mViewPager.setAdapter(pagerAdapter);
 

I've got an activity which initially hosts a ViewPager, hooked up to a FragmentPagerAdapter.

When the user clicks on an item inside the ViewPager's child fragment, I'm using a FragmentTransaction to replace an empty container view with a new Fragment which I want to navigate to.

If I use addToBackStack() on the transaction, commit the transaction and then navigate back, I am not returned to the ViewPager's views (the initial layout).

If I don't use addToBackStack() on the transaction, commit the transaction and then navigate back, the application exits.

It seems apparent that the ViewPager is not added to the backstack (which is not that surprising as it isn't a fragment in itself).. But I would expect the default behaviour would be that the back press takes me back to that activities initial View (the ViewPager).

Based on what I've read, it seems that perhaps because a fragment transaction is taking place, the ViewPager or PagerAdapter loses track of which fragment should be on display.

I'm really confused with this, but I ended up creating a huge mess of code overriding the onBackPress and showing and hiding the viewpager views. I would've thought there is a simpler way to use default behaviours to perform the appropriate navigation.

tl;dr

A is a Viewpager hosting fragments. B is a new Fragment.

When I replace A with B, and then press back, I expect to navigate back to A, but that is not happening.

Any advice would be much appreciated.

Code:

MainActivity:

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

    }

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

main xml (containing 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>

解决方案

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