50

ViewPagerは3つのFragmentsを持ち、それぞれList(またはGrid)を示します。ネストされたフラグメント(Android 4.2)を使用してViewPager内にフラグメントを追加する方法

新しいAndroid API level 17(Jelly Bean 4.2)では、機能の1つがNested Fragmentsです。新機能の説明は言う:

あなたが左右スワイプフラグメントを作成するためにViewPagerを使用して は、画面スペースの大半を消費した場合、あなたは今、各フラグメントページに断片 を挿入することができます。

私は右の理解のであれば、今、私は内部(例えば内部のボタンで)FragmentsViewPagerを作成することができ、そしてときに、ユーザーのボタンを押すと、この新機能を使用してViewPagerを失うことなく、別のFragmentを示しました。

私はこのいくつかの異なる方法を実装しようとしましたが、私はそれを動作させることができません...誰かがこれを実装する方法の簡単な例を追加できますか?

PS:私はこの方法でやってみたいと思っています。getChildFragmentManagerで働いています。

+3

この先週の早い段階でサンプルを作成します。それまでに誰も答えなくなったことがないなら、その時に何かを投稿しようとします。 – CommonsWare

+0

@ CommonsWare – sabadow

答えて

93

正しいxmlレイアウトを作成したとします。他のフラグメントによってホストされているViewPagerにフラグメントを表示するのは非常に簡単です。

コードは、親フラグメントで次のようになります。

@Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     return inflater.inflate(R.layout.fragment_parent, container, false); 
    } 

    @Override 
    public void onViewCreated(View view, Bundle savedInstanceState) { 
     super.onViewCreated(view, savedInstanceState); 

     ViewPager mViewPager = (ViewPager) view.findViewById(R.id.viewPager); 
     mViewPager.setAdapter(new MyAdapter(getChildFragmentManager())); 
    } 

    public static class MyAdapter extends FragmentPagerAdapter { 

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

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

     @Override 
     public Fragment getItem(int position) { 
      Bundle args = new Bundle(); 
      args.putInt(TextViewFragment.POSITION_KEY, position); 
      return TextViewFragment.newInstance(args); 
     } 
    } 

FragmentPagerAdapterをインスタンス化する際にFragment.getChildFragmentManager()を使用することが重要です。また、子フラグメントにFragment.setRetainInstance()を使用できない場合、例外が発生します。ソースコードはで見つけることができ

https://github.com/marcoRS/nested-fragments

+1

SherlockFragmentsとsupport.v4 release11でViewPagerを含むフラグメントを作成すると問題が発生していますが、ViewPagerのコンテンツはアダプタ経由で設定されますが、子フラグメントは表示されません:( – straya

+0

Straya。 SherlockFragmentsと私はエラーが表示されませんでした。あなたが見ているエラーは何ですか? –

+1

Heya、私もAndroid-ViewPagerIndicatorをミックスしています。ViewPagerとViewPagerIndicatorが表示されます(FragmentにViewPagerの上にTextViewがあり、Fragmentが表示されていることがわかります)が、ViewPagerの子Fragment(FragmentPagerAdapter経由で提供)は表示されません。私はページ間でスワイプすることができます。 – straya

11

編集: あなたはまだネストされた断片を使用することができますが、いくつかの変更が必要とされているViewPagerのページのすべてのコンテンツを置き換えたい場合。 (ViewPagerを設定し、FragmentActivityPagerAdapterは、前のコードスニペットと同じである)以下のサンプルを確認してください:それが動作ざっと見で

// this will act as a fragment container, representing one page in the ViewPager 
public static class WrapperFragment extends Fragment implements 
     ReplaceListener { 

    public static WrapperFragment newInstance(int position) { 
     WrapperFragment wp = new WrapperFragment(); 
     Bundle args = new Bundle(); 
     args.putInt("position", position); 
     wp.setArguments(args); 
     return wp; 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 
     FrameLayout fl = new FrameLayout(getActivity()); 
     fl.setId(10000); 
     if (getChildFragmentManager().findFragmentByTag("initialTag") == null) { 
      InitialInnerFragment iif = new InitialInnerFragment(); 
      Bundle args = new Bundle(); 
      args.putInt("position", getArguments().getInt("position")); 
      iif.setArguments(args); 
      getChildFragmentManager().beginTransaction() 
        .add(10000, iif, "initialTag").commit(); 
     } 
     return fl; 
    } 

    // required because it seems the getChildFragmentManager only "sees" 
    // containers in the View of the parent Fragment. 
    @Override 
    public void onReplace(Bundle args) { 
     if (getChildFragmentManager().findFragmentByTag("afterTag") == null) { 
      InnerFragment iif = new InnerFragment(); 
      iif.setArguments(args); 
      getChildFragmentManager().beginTransaction() 
        .replace(10000, iif, "afterTag").addToBackStack(null) 
        .commit(); 
     } 
    } 

} 

// the fragment that would initially be in the wrapper fragment 
public static class InitialInnerFragment extends Fragment { 

    private ReplaceListener mListener; 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 
     mListener = (ReplaceListener) this.getParentFragment(); 
     LinearLayout ll = new LinearLayout(getActivity()); 
     Button b = new Button(getActivity()); 
     b.setGravity(Gravity.CENTER_HORIZONTAL); 
     b.setText("Frame " + getArguments().getInt("position")); 
     b.setOnClickListener(new OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       Bundle args = new Bundle(); 
       args.putInt("positionInner", 
         getArguments().getInt("position")); 
       if (mListener != null) { 
        mListener.onReplace(args); 
       } 
      } 
     }); 
     ll.setOrientation(LinearLayout.VERTICAL); 
     ll.addView(b, new LinearLayout.LayoutParams(250, 
       LinearLayout.LayoutParams.WRAP_CONTENT)); 
     return ll; 
    } 

} 

public static class InnerFragment extends Fragment { 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 
     TextView tv = new TextView(getActivity()); 
     tv.setText("InnerFragment in the outher Fragment with position " 
       + getArguments().getInt("positionInner")); 
     return tv; 
    } 

} 

public interface ReplaceListener { 
    void onReplace(Bundle args); 
} 

が、私はそれをテストしていないなどの問題が表示されることがあります過ぎる。

誰かがこれを行う方法の簡単な例を表示できますか? Commonswareあなたは以下のコードを試すことができ、より精巧なサンプルが付属してまで、ネストされた断片を使用して

は、とても簡単そうです:

public class NestedFragments extends FragmentActivity { 

    @Override 
    protected void onCreate(Bundle arg0) { 
     super.onCreate(arg0); 
     ViewPager vp = new ViewPager(this); 
     vp.setId(5000); 
     vp.setAdapter(new MyAdapter(getSupportFragmentManager())); 
     setContentView(vp); 
    } 

    private static class MyAdapter extends FragmentPagerAdapter { 

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

     @Override 
     public Fragment getItem(int position) { 
      return WrapperFragment.newInstance(position); 
     } 

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

    public static class WrapperFragment extends Fragment { 

     public static WrapperFragment newInstance(int position) { 
      WrapperFragment wp = new WrapperFragment(); 
      Bundle args = new Bundle(); 
      args.putInt("position", position); 
      wp.setArguments(args); 
      return wp; 
     } 

     @Override 
     public View onCreateView(LayoutInflater inflater, ViewGroup container, 
       Bundle savedInstanceState) { 
      LinearLayout ll = new LinearLayout(getActivity()); 
      FrameLayout innerFragContainer = new FrameLayout(getActivity()); 
      innerFragContainer.setId(1111); 
      Button b = new Button(getActivity()); 
      b.setText("Frame " + getArguments().getInt("position")); 
      b.setOnClickListener(new OnClickListener() { 

       @Override 
       public void onClick(View v) { 
        InnerFragment innerFragment = new InnerFragment(); 
        Bundle args = new Bundle(); 
        args.putInt("positionInner", 
          getArguments().getInt("position")); 
        innerFragment.setArguments(args); 
        FragmentTransaction transaction = getChildFragmentManager() 
          .beginTransaction(); 
        transaction.add(1111, innerFragment).commit(); 
       } 
      }); 
      ll.setOrientation(LinearLayout.VERTICAL); 
      ll.addView(b, new LinearLayout.LayoutParams(
        LinearLayout.LayoutParams.MATCH_PARENT, 
        LinearLayout.LayoutParams.WRAP_CONTENT)); 
      ll.addView(innerFragContainer, new LinearLayout.LayoutParams(
        LinearLayout.LayoutParams.MATCH_PARENT, 
        LinearLayout.LayoutParams.MATCH_PARENT)); 
      return ll; 
     } 

    } 

    public static class InnerFragment extends Fragment { 

     @Override 
     public View onCreateView(LayoutInflater inflater, ViewGroup container, 
       Bundle savedInstanceState) { 
      TextView tv = new TextView(getActivity()); 
      tv.setText("InnerFragment in the outher Fragment with position " 
        + getArguments().getInt("positionInner")); 
      return tv; 
     } 

    } 

} 

私は怠け者だったとコードですべてのものを作ったが、私はそれができると確信しています膨らんだxmlレイアウトで作業します。

+1

ありがとう、私はXMLレイアウトファイルで使用するようリコメンドしようとしていますし、うまくいくようです; – sabadow

+0

'transaction.add(1111、innerFragment).commit() ;ボタンが押されるたびにレイアウトの階層を追加するので、 'replace'メソッドを使うべきです。また、XMLレイアウトを使用して**すべての** **ページの内容を置き換えるように変更しようとする例をリファクタリングします。しかし、私はまだそれを作ることができませんでした、常に 'ボタン'を維持する。なにか提案を? – sabadow

+0

@Luksprog:これは私が考えていたシナリオではありません。私は、 'ViewPager'自体がフラグメントによってホストされ、そのページのフラグメントを持つサンプルで作業するつもりです。それは 'getChildFragmentManager()'を 'PagerAdapter'に渡すだけですが、最初に試してみたいと思います。あなたの例は、他のフラグメントを保持する 'ViewPager'フラグメントを保持していることを示しています。完全に合理的です。 – CommonsWare

6

私がやりたいことここに3つの要素とインデックス2と3のための2つのサブ要素でViewPagerを作成しています。..

enter image description here

私はStackOverFlowの以前の質問と回答の助けを借りてこれを実装しました。ここにリンクがあります。

ViewPagerChildFragments

+0

方向の変更にクラッシュするなど、このコードにいくつかのバグがあります。あなたはそれらを修正したことがありますか? –

+0

このコードでバグを修正したユーザーは、アプリがオリエンテーションの変更によってクラッシュする可能性がありますか? –

関連する問題