web-dev-qa-db-ja.com

ViewPagerをフラグメントで置き換える-次に戻る

FragmentPagerAdapterに接続された、最初にViewPagerをホストするアクティビティがあります。

ユーザーがViewPagerの子フラグメント内のアイテムをクリックすると、FragmentTransactionを使用して、空のコンテナービューを移動先の新しいフラグメントに置き換えます。

トランザクションでaddToBackStack()を使用し、トランザクションをコミットしてから戻ると、ViewPagerのビュー(初期レイアウト)に戻りません。

トランザクションでaddToBackStack()を使用せず、トランザクションをコミットしてから戻ると、アプリケーションが終了します。

ViewPagerがバックスタックに追加されていないようです(それ自体はフラグメントではないので、これは驚くべきことではありません)。表示(ViewPager)。

私が読んだ内容に基づいて、おそらくフラグメントトランザクションが行われているために、ViewPagerまたはPagerAdapterがどのフラグメントを表示する必要があるかを追跡できなくなっているようです。

私はこれに本当に混乱していますが、onBackPressをオーバーライドして、viewpagerビューを表示および非表示にするコードの巨大な混乱を作成してしまいました。デフォルトの動作を使用して適切なナビゲーションを実行する簡単な方法があると思ったでしょう。

tl; dr

AはフラグメントをホストするViewpagerです。 Bは新しいフラグメントです。

AをBに置き換えてから押し戻すと、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();

    }

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

メイン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>
30
Tim Malseed

私もこの同じ問題を長い間抱えていました。解決策は非常にシンプルであることがわかり、ViewPager Visibilityを使用したハックは必要ありません。私はこの他に説明されていますSO関連質問: popBackStackの後でViewPagerのフラグメントが復元されない

ただし、簡単にするために必要なことは、getSupportFragmentManager()ではなく、ViewPagerアダプターでgetChildFragmentManager()を使用することだけです。したがって、これの代わりに:

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

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

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

これをして:

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

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

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

更新:
これは「Androidの方法」ではなく、リストビューの場合のユーザーエクスペリエンスが低下します。代わりに、新しいアクティビティを作成します。

この問題の簡単な解決策を探している人々のために、私がしたことを要約します。

私のアーキテクチャ:

  • FragmentActivityのViewPager(実際にはActionBarActivity、ActionBarサポート用。ただし、ActionBarActivityはFragmentActivityを実装します)。

  • 2つのタブ:

    • Fragmentを拡張するFragmentContainer1。
    • Fragmentを拡張するFragmentContainer2。

FragmentContainerごとに、たとえばonCreateメソッドでgetChildFragmentManagerを呼び出し、このコンテナに表示するフラグメントを追加します。

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インスタンスが返されます。

以上です!私は専門家ではありませんので、ご意見やご感想がありましたらお気軽にどうぞ。

9
Menerve

これを達成するために私が見つけた唯一の方法は、次のことです。

ViewPagerから離れてナビゲートする場合は、Visiblity.GONEを使用してviewPagerをビューの外に送ります。フラグメントトランザクションをバックスタックに追加します。

(バックプレスを介して)viewPager画面に戻るときに、onBackPressedをオーバーライドします。バックスタックにあるフラグメントの数を確認できます。フラグメントトランザクションが発生する前にviewPagerが最初のビューだった場合は、フラグメントバックスタックエントリカウントが0かどうかを確認できます。

fragmentManager.getBackStackEntryCount()== 0、バックスタックにフラグメントがありません。

そのステートメントがtrueの場合は、Visibility.VISIBLEを使用してviewPagerを表示に戻します。

3
Tim Malseed

私は非常によく似た問題を抱えていると思います。

FragmentManagersはいくぶん階層的に振る舞うようです。私がこの問題を解決した方法は、ViewPager内のフラグメントから取得できるものではなく、コンテナーとViewPagerをホストするアクティビティからの「メイン」FragmentManagerを使用することでした。

これを行うために、私は以下を使用しました:

this.getActivity().getSupportFragmentManager()

ここで、thisはFragmentのインスタンスです。

ここで、ViewPager内のアイテムから「replace」トランザクションを使用して他のフラグメントに移動すると、戻ったときに、ViewPagerを残した状態で表示できます。

より完全なコードサンプルは次のようになります。

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

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

transaction.commit();
0
Tadas Šubonis

ViewPagerを開始できるFragmentsを含むActivitiesを使用している場合は、次のようにして、ヒットしたときにViewPagerの位置に適切に戻ることができます。上記のActivityから戻るまたは上に移動します(Activitiesに対して上方向のナビゲーションが宣言されていると想定します)。

まず、新しいViewPagerを開始するには、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(MenuItem item)

0
Sakiboy