50

我有一個ViewPager具有三個Fragments,每一個示出了List(或Grid)。如何添加ViewPager內使用嵌套片段(Android的4.2)的片段

在新的Android API level 17(Jelly Bean 4.2)中,其中一個功能是Nested Fragments。新功能介紹說:

如果使用ViewPager創建輕掃左,右和 消耗了大部分的屏幕空間的片段,你現在可以插入片段 到每個片段頁。

所以,如果我理解正確的,現在我可以創建一個FragmentsViewPager(裏面例如按鈕)內,當用戶按下按鈕顯示另一Fragment不使用這個新功能鬆ViewPager

我已經花費了我早上想實現這一幾種不同的方式,但我不能得到它的工作...有人可以添加如何實現一個簡單的例子?

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

我看到問題做到這一點(片段包含ViewPager,即)與SherlockFragments和support.v4版本11,ViewPager內容通過適配器設置,但兒童片段不顯示:( – straya

+0

嗨Straya。我測試了我的例子SherlockFragments和我沒有看到錯誤,你看到的錯誤是什麼? –

+1

Heya,我也有Android-ViewPagerIndicator。顯示ViewPager和ViewPagerIndicator(我在它的Fragment中有一個位於ViewPager上方的TextView,所以我可以看到該Fragment被顯示),但ViewPager的子Fragments(通過FragmentPagerAdapter提供)不顯示。我可以在頁面之間滑動,指示器更新但仍然不是子片段。 – straya

11

編輯: 如果你想更換一個網頁上的所有內容在一個ViewPager你仍然可以使用嵌套的片段,但還需要一些改變。檢查下面的示例(該FragmentActivity,設置ViewPagerPagerAdapter是相同的代碼上面的代碼片段):

// 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佈局,並嘗試改變以替換** all **頁面的內容。但是我還沒有做到,總是把'Button'放在最前面。任何建議? – sabadow

+0

@Luksprog:這不是我想到的情景。我將着手處理一個樣本,其中'ViewPager'本身由一個片段承載,併爲其頁面提供片段。 *應該只是將'getChildFragmentManager()'傳遞給'PagerAdapter'的問題,但我想先嚐試一下。你的例子展示了一個持有片段的'ViewPager',它們保存着其他片段 - 完全合理,而不是當我讀到這個問題時我想的。 – CommonsWare

6

我創建了一個ViewPager 3個要素,爲指數2和3,在這裏2個元素是我想做的事..

enter image description here

我已經在StackOverFlow的以前的問題和答案的幫助下實現了這一點,這裏是鏈接。

ViewPagerChildFragments

+0

有一些錯誤與此代碼,如它崩潰的變化方向。你有沒有修復它們? –

+0

是否有人設法修復了導致應用程序在方向更改時崩潰的代碼的錯誤? –