Fragment中的ViewPager--使用Nested Fragment

目的:在Fragemnt中放入ViewPager,可在功能表中切換fragment頁面,而子Fragment中又有可滑動的pager



首先有幾個需要注意的地方

1.用來實做ViewPager的Fragment的類別引用android.app.Fragment,而非support.v4.app.Fragment,否則無法使用巢狀fragment
2.在API 23以前使用Fragment中類別OnAttach(Activity activity),API 23以後才用OnAttach(Context Context)

結構圖
先提供Adapter每一個子頁面的資料,viewpager就可決定要顯是哪一個頁面。
而viewpager本身也是放在一個fragment中,所以UI可以更靈活操作什麼時候要顯示這個畫面


首先需要新增一個放置ViewPager的父Fragment使用List集合加入每一個頁面代表的Fragment
宣告一個自訂的PagerAdapter ,傳入FragmentManger和List建構物件
注意:因為提供page的所代表的Fragment是子Fragment所以提供的Manager要用getChildFragmentManager()
public class fragment_slide extends Fragment {
    private ViewPager mViewPager;
    private View view;
    private android.support.design.widget.TabLayout mTabs;
    Activity activity;
    @Override    public void onActivityCreated(Bundle savedInstantState) {
        super.onActivityCreated(savedInstantState);

        initialTabs();
        initialViewPager();
    }
    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstantState)
    {
        view = inflater.inflate(R.layout.slide_layout,container,false);
        return view;
    }

    @Override    public void onAttach(Activity activity) {
        super.onAttach(activity);
        Log.d("FragmentSlide", "onAttach");
        this.activity = activity;
    }


    private void initialTabs() {
        mTabs = (android.support.design.widget.TabLayout) view.findViewById(R.id.tabs);
        mTabs.addTab(mTabs.newTab().setText("Tab 1"));
        mTabs.addTab(mTabs.newTab().setText("Tab 2"));
        mTabs.addTab(mTabs.newTab().setText("Tab 3"));
        mTabs.addTab(mTabs.newTab().setText("Tab 4"));
    }
    private void initialViewPager() {
        List<Fragment> fragments = new ArrayList<Fragment>();
        fragments.add(FragmentPage.newInstance("Page1",1));
        fragments.add(FragmentPage.newInstance("Page2",2));
        fragments.add(FragmentPage.newInstance("Page3",3));
        fragments.add(FragmentPage.newInstance("Page4",4));
        PagerAdapter myPagerAdapter = new azuresky.smartdrug.Adapters.PagerAdapter(getChildFragmentManager(),fragments);
        mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
        mViewPager.setAdapter(myPagerAdapter);
        mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabs));

    }
}


PagerAdapter是用來提供ViewPager資料的容器,因為我們希望把page放在Fragment中,
所以這邊有兩種選擇
1.繼承FragmentPagerAdapter:適合頁面數量少的情況,因為每個 Fragment 
頁面會持續的被保留在記憶體中,在頁面不可見(not visible)的情況下,view 會被銷毀,
但整個 Fragment 仍然存在。
2.繼成FragmentStatePagerAdapter:使用較多頁面,在頁面不可見(not visible)的情況下
,整個 Fragment 都會被銷毀,只保留狀態 (state),因此不會佔用大量的記憶體。




public class PagerAdapter extends FragmentStatePagerAdapter {
    private List<Fragment> fragments;
    public PagerAdapter(FragmentManager fm,List<Fragment> fragments) {
        super(fm);
        this.fragments = fragments;
        Log.d("PagerAdapter",fm.toString());
        Log.d("PagerAdapter","");
    }
    @Override    public android.app.Fragment getItem(int position) {
        return fragments.get(position);
    }
    @Override    public int getCount() {
        return 4;
    }
}
接著就是建立每一個頁面要放置的Fragment 使用newInstance這個方法來提供Fragment
物件實例,透過setArgument來設定bundle給Fragment 1.在 onCreate() 中可用getArguments()來取得bundle 2.在 onCreateView() 中指定layout 3.在 onViewCreated() 中可以對view做動作 如果需要 Activity 的資源,則在 onActivityCreated() 方法中取用。
使用FragmentStatePagerAdapter可以使用Log來看Fragment的生命週期,
可以發現Adapter知會預先載入當前畫面的前後一個頁面。
其他已經create的view都會onDestroyView->onDestroy->onDetach
public class FragmentPage extends Fragment{
private static final String TITLE = "TITLE";
    private static final String RESID= "RESID";
    private String title;
    public static final FragmentPage newInstance(String title, int resId){
        FragmentPage fg = new FragmentPage();
        Bundle bd = new Bundle();
        bd.putString(TITLE,title);
        bd.putInt(RESID, resId);
        fg.setArguments(bd);
        return  fg;
    }

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

    @Override    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        TextView text1 = (TextView)view.findViewById(R.id.text1);
        text1.setText(getArguments().getString(TITLE));
    }
執行結果








留言

這個網誌中的熱門文章

Arduino記憶體的二三事