Android編程權(quán)威指南(第二版)學習筆記(十一)—— 第11章 使用 ViewPager

本章介紹了如何使用 ViewPager(準確地說,應(yīng)該是使用了 FragmentStatePagerAdapter 的簡單的 ViewPager)。

GitHub 地址:
完成第十一章

1. ViewPager 和 PagerAdapter

ViewPager 在某種程度上類似于 RecyclerView,它們都需要借助于 Adapter 來支持,ViewPager 需要的是 PagerAdapter。

ViewPager 與 PagerAdapter 之間的配合比 RecyclerView 與其 Adapter 之間復(fù)雜得多。但是對于本章而言,因為使用的是 PagerAdapter 的子類 FragmentStatePagerAdapter,它能協(xié)助處理很多細節(jié)問題.

FragmentStatePagerAdapter 化繁為簡,提供了兩個有用的方法:getCount()getItem (int)

調(diào)用 getCount() 方法顧名思義就是獲取數(shù)據(jù)集的大小。調(diào)用 getItem(int) 方法,返回的是應(yīng)該是和數(shù)據(jù)綁定的Fragment,一般來說會將其和數(shù)據(jù)集的位置相對應(yīng)。

使用步驟:

  • 布局文件,使用 ViewPager(因為只有支持包而沒有內(nèi)置,所以不像 fragment 需要選擇)
  • 在代碼中聲明 ViewPager 變量并引用
  • 本書中使用的是匿名 FragmentStatePagerAdapter 類,在其中直接重寫了兩個關(guān)鍵方法,然后就可以使用了。
// 引用 ViewPager
mViewPager = (ViewPager) findViewById(R.id.activity_crime_pager_view_pager);
// 獲取數(shù)據(jù)集
mCrimes = CrimeLab.get(this).getCrimes();
// 獲取 FragmentManager
FragmentManager fragmentManager = getSupportFragmentManager();
// 使用匿名內(nèi)部類來引用 FragmentStatePagerAdapter,構(gòu)造方法的參數(shù)是 FragmentManager
mViewPager.setAdapter(new FragmentStatePagerAdapter(fragmentManager) {
    @Override
    public Fragment getItem(int position) {
        Crime crime = mCrimes.get(position);
        return CrimeFragment.newInstance(crime.getId());
    }

    @Override
    public int getCount() {
        return mCrimes.size();
    }
});

// 設(shè)置完 Adapter 以后,就要選擇當前的數(shù)據(jù)啦~這就是上一個  Activity 傳遞進來的數(shù)據(jù),我就不予贅述了。
for (int i = 0; i < mCrimes.size(); i++) {
    if (mCrimes.get(i).getId().equals(crimeId)) {
        mViewPager.setCurrentItem(i);
        break;
    }
}

2. FragmentStatePagerAdapter 與 FragmentPagerAdapter

FragmentPagerAdapter 是另外一種可用的 PagerAdapter , 其用法與 FragmentStatePagerAdapter 基本一致。唯一的區(qū)別在于:卸載不再需要的 fragment 時,各自采用的處理方法有所不同。

FragmentStatePagerAdapter會銷毀不需要的 fragment。事務(wù)提交后,activity 的 FragmentManager 中的 fragment 會被徹底移除。FragmentStatePagerAdapter 類名中的“state”表明:在銷毀 fragment 時,可在 onSaveInstanceState(Bundle) 方法中保存 fragment 的 Bundle 信息。用戶切換回來時,保存的實例狀態(tài)可用來恢復(fù)生成新的fragment。

相比之下,FragmentPagerAdapter 有不同的做法。對于不再需要的 fragment,FragmentPagerAdapter 會選擇調(diào)用事務(wù)的 detach(Fragment) 方法來處理它,而非 remove(Fragment) 方 法。也就是說,FragmentPagerAdapter 只是銷毀了 fragment 的視圖,fragment 實例還保留在 FragmentManager。因此,FragmentPagerAdapter 創(chuàng)建的 fragment 永遠不會被銷毀。

選擇哪種adapter取決于應(yīng)用的要求。通常來說,使用 FragmentStatePagerAdapter 更節(jié)省內(nèi)存。CriminalIntent 應(yīng)用需顯示大量crime記錄,每份記錄最終還會包含圖片。在內(nèi)存中保存所有信息顯然不合適,因此我們選擇使用 FragmentStatePagerAdapter

另一方面,如果用戶界面只需要少量固定的fragment,則 FragmentPagerAdapter 是個安全、 合適的選擇。

最常見的例子為分頁顯示用戶界面。例如,某些應(yīng)用的明細視圖所含內(nèi)容較多,通 常需分兩頁顯示。這時就可以將這些明細信息分拆開來,以多頁面的形式展現(xiàn)。顯然,為用戶界面添加支持滑動切換的 ViewPager,能增強應(yīng)用的觸摸體驗。此外,將 fragment 保存在內(nèi)存中,更易于管理控制層的代碼。對于這種類型的用戶界面,每個 activity 通常只有兩三個 fragment,基本不用擔心有內(nèi)存不足的風險。

3. 深入學習:ViewPager 的工作原理

什么時候需要自己實現(xiàn)PagerAdapter接口呢?需要ViewPager托管非 fragment 視圖時,就需要實現(xiàn)原生 PagerAdapter 接口。

PagerAdapter 要比 RecyclerView 的 Adapter復(fù)雜得多,因為它要處理更多的視圖管理工作。
PagerAdapter 不使用可返回視圖的onBindViewHolder(...)方法,而是使用下列方法:

public Object instantiateItem(ViewGroup container, int position)

public void destroyItem(ViewGroup container, int position, Object object)

public abstract boolean isViewFromObject(View view, Object object)
  • PagerAdapter.instantiateItem(ViewGroup, int)方法告訴 PagerAdapter 創(chuàng)建指定位置的列表項視圖,然后將其添加給 ViewGroup 視圖容器,而 destroyItem(ViewGroup, int, Object) 方法則告訴 PagerAdapter 銷毀已建視圖。(注意,instantiateItem(ViewGroup, int) 方法并不要求立即創(chuàng)建視圖。因此,PagerAdapter 可自行決定何時創(chuàng)建視圖。)

  • 視圖創(chuàng)建完成后,ViewPager 會在某個時間點注意到它。為確定該視圖所屬的對象,ViewPager 會調(diào)用 isViewFromObject(View, Object) 方法。這 里 , Object 參數(shù)是 instantiateItem(ViewGroup,int) 方法返回的對象。因此,假設(shè) ViewPager 調(diào)用instantiateItem(ViewGroup, 5) 方法返回一個 A 對象,那么只要傳入的 View 參數(shù)是第5個對象的視圖,isViewFromObject(View, A) 方法就應(yīng)返回true值,否則返回false值。

對 ViewPager 來說,這是一個復(fù)雜的過程,但對于PagerAdapter來說,這算不上什么。因為PagerAdapter只要能夠創(chuàng)建、銷毀視圖以及識別視圖來自哪個對象即可。這樣的要求顯然很寬松,因而PagerAdapter 能夠比較自由地通過 instantiateItem(ViewGroup, int) 方法創(chuàng)建并添加新的fragment ,然后返回可以跟蹤管理的 Object(fragment) 。

以下為isViewFromObject (View, Object)方法的具體實現(xiàn):

@Override
public boolean isViewFromObject(View view, Object object) {
    return ((Fragment)object).getView() == view;
}

可以看到,每次需要使用ViewPager時,都要覆蓋實現(xiàn)PagerAdapter的這些方法,這真是一種磨難。所幸我們有 FragmentPagerAdapterFragmentStatePagerAdapter 這么便利的類。


GitHub Page: kniost.github.io
簡書:http://www.itdecent.cn/u/723da691aa42

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容