ViewPager 使用

學(xué)習(xí)了 ViewPager,在此做個(gè)總結(jié),主要包括一下幾個(gè)方面:

  • ViewPager 簡介
  • ViewPager 的使用
  • FragmentStatePagerAdapter 和 FragmentPagerAdapter
  • ViewPager 的工作原理
  • 恢復(fù) CrimeFragment 的邊距
  • 添加 Jump to First 按鈕和 Jump to Last 按鈕

ViewPager 簡介

  1. ViewPager 是 android 擴(kuò)展包 v4 包中的類,這個(gè)類可以讓用戶左右切換當(dāng)前的 view
  2. ViewPager 直接繼承了 ViewGroup,所有它是一個(gè)容器類,可以在其中添加其他的 view 類。
  3. ViewPager 需要一個(gè) PagerAdapter 適配器類給它提供數(shù)據(jù)。
  4. ViewPager 經(jīng)常和 Fragment 一起使用,并且提供了專門的 FragmentPagerAdapter 和 FragmentStatePagerAdapter 類供 Fragment 中的 ViewPager 使用。

ViewPager 的使用

因?yàn)橹暗姆庋b,CrimeFragment 類可以不做修改直接使用。接下來看我們需要完成的任務(wù)。

  1. 創(chuàng)建 CrimePagerActivity 類
  2. 在 CrimePagerActivity 類中關(guān)聯(lián)使用 ViewPager 及其 Adapter
  3. 修改 CrimeHolder.onClick(...) 方法,轉(zhuǎn)而啟動(dòng) CrimePagerActivity

創(chuàng)建 CrimePagerActivity 類

CrimePagerActivity.java

public class CrimePagerActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_crime_pager);
    }

布局文件

activity_crime_pager.xml

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/crime_view_pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".CrimePagerActivity">
</android.support.v4.view.ViewPager>

在 CrimePagerActivity 類中關(guān)聯(lián)使用 ViewPager 及其 Adapter

ViewPager 某種程度上與 RecyclerView 類似,都需要借助 Adapter 提供視圖。因?yàn)?ViewPager 與 PagerAdapter 間的配合要復(fù)雜很多,這里先用 FragmentPagerAdapter,它能處理很多細(xì)節(jié)的問題

FragmentPagerAdapter 提供了兩個(gè)有用的方法:getCount() 和 getItem(int)。調(diào)用 getItem(int) 方法,獲取并顯示 crime 數(shù)組中指定位置的 Crime 時(shí),它會(huì)返回配置過的 CrimeFragment 來顯示指定的 Crime。
CrimePagerActivity.java

public class CrimePagerActivity extends AppCompatActivity {

    private ViewPager mViewPager;
    private List<Crime> mCrimes;
    
     @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_crime_pager);

        mViewPager = (ViewPager) findViewById(R.id.crime_view_pager);

        mCrimes  =CrimeLab.get(this).getCrimes();
        FragmentManager fragmentManager = getSupportFragmentManager();
        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();
            }
        });

解釋一下上面的代碼,在 activity 視圖中找到 ViewPager 后,我們從 CrimeLab 獲取數(shù)據(jù)集,然后獲取 FragmentManager 的實(shí)例。接下來,設(shè)置 adapter 為 FragmentStatePagerAdapter 的一個(gè)匿名實(shí)例。創(chuàng)建 FragmentStatePagerAdapter 需要 FragmentManager。如前所述,qiansuoshuFragmentStatePagerAdapter 是我們的代理,代理首先將 getItem(int) 方法返回的 fragment 添加給 activity,然后才能使用 fragment 完成自己的工作。

代理究竟做了哪些工作呢?簡單來說就是將返回的 fragment 添加給托管 activity,并幫助 ViewPager 找到 fragment 的視圖一一對(duì)應(yīng)。getItem(int) 方法首先獲取指定位置的 Crime 實(shí)例,然后利用該 Crime 實(shí)例的 ID 創(chuàng)建并返回一個(gè)經(jīng)過有效配置發(fā) CrimeFragment。

修改 CrimeHolder.onClick(...) 方法,轉(zhuǎn)而啟動(dòng) CrimePagerActivity

CrimePagerActivity.java

 private static final String EXTRA_CRIME_ID = "com.bignerdranch.android.criminalintent.crime_id";

    private ViewPager mViewPager;
    private List<Crime> mCrimes;

    public static Intent newIntent(Context packageContext, UUID crimeId){
        Intent intent = new Intent(packageContext,CrimePagerActivity.class);
        intent.putExtra(EXTRA_CRIME_ID,crimeId);
        return intent;
    }
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_crime_pager);
        
        UUID crimeId = (UUID)getIntent().getSerializableExtra(EXTRA_CRIME_ID) ;
        ...
    }

修改 CrimeHolder.onClick(...) 方法,轉(zhuǎn)而啟動(dòng) CrimePagerActivity

CrimePagerActivity.java

    @Override
    public void onClick(View view) {
       // Intent intent = CrimeActivity.newIntent(getActivity(),mCrime.getId());
        Intent intent = CrimePagerActivity.newIntent(getActivity(),mCrime.getId());
        mPosition = this.getAdapterPosition();
        startActivity(intent);
    }

最后在 AndroidManifest.xml中刪除 CrimeActivity 的代碼。

注意,目前 ViewPager 還不完美,ViewPager 默認(rèn)只顯示 PagerAdapter 中的第一個(gè)列表項(xiàng)。要顯示選中的列表項(xiàng)需要在 CrimePagerActivity.onCreate(Bundle) 末尾添加以下代碼。

CrimePagerActivity.java


for (int i = 0; i < mCrimes.size(); i++){
    if (mCrimes.get(i).getId().equals(crimeId)){
        mViewPager.setCurrentItem(i);
        break;
    }
}

FragmentStatePagerAdapter 和 FragmentPagerAdapter

FragmentPagerAdapter 是另一種可用的 PagerAdapter,其用法和 FragmentStatePagerAdapter 基本一致,只是在卸載不需要的 fragment 時(shí),各自采用的處理方法不同。

FragmentStatePagerAdapter 會(huì)銷毀不需要的 fragment,而 FragmentPagerAdapter 是調(diào)用 detach(Fragment) 方法來處理它,只是銷毀了 fragment 的視圖,而 fragment 的實(shí)例由 FragmentManager 維護(hù),因此,F(xiàn)ragmentPagerAdapter 創(chuàng)建的 fragment 永遠(yuǎn)不會(huì)被銷毀。

所以當(dāng)數(shù)據(jù)量大時(shí),可以選擇 FragmentStatePagerAdapter,用戶界面只有少量固定的 fragment 時(shí),可以選擇 FragmentPagerAdapter。

ViewPager 的工作原理

首先明確一點(diǎn),要實(shí)現(xiàn)自己的 PagerAdapter 接口時(shí),就需要了解它的工作原理,那么什么時(shí)候需要實(shí)現(xiàn) PagerAdapter 接口呢?當(dāng)需要托管非 fragment 視圖時(shí)(如圖片),就需要實(shí)現(xiàn)原生的 PagerAdapter。

為什么使用 ViewPager而不是 RecyclerView?

Adapter 需要我們及時(shí)提供 View。然而,覺得 fragment 創(chuàng)建的是 FragmentManager。因此,當(dāng) RecyclerView 要求 Adapter 提供 fragment 視圖時(shí)。我們無法立即創(chuàng)建 fragment 并提供其視圖。這就是 PagerView 存在的理由。

下面看它的內(nèi)部實(shí)現(xiàn)。

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)

instantiateItem(ViewGroup,int) 方法是告訴 pager adapter 創(chuàng)建指定位置的列表項(xiàng)視圖,但并不要求立即創(chuàng)建視圖,pager adpter 可以自己決定何時(shí)創(chuàng)建視圖。然后將其添加給 ViewGroup,而 destroyItem(ViewGroup,int,Object) 方法則是告訴 pager adapter 視圖已經(jīng)銷毀(FragmentStatePagerAdapter 和 FragmentPagerAdapter 的不同主要是在這里)。

詳情可以參考此鏈接:
ViewPager 全面剖析及使用詳解

視圖創(chuàng)建后,ViewPager 會(huì)在某個(gè)時(shí)間點(diǎn)看到它,為了確定該視圖所屬的對(duì)象,ViewPager 會(huì)調(diào)用 isViewFromObject(View,Object),這里的 object 是 instantiateItem(ViewGroup,int) 方法返回的對(duì)象。

恢復(fù) CrimeFragment 的邊距

把 fragment_crime.xml 下的 LinearLayout 的 android:layout_margin="16dp" 改成 android:padding="16dp"。

GitHub地址

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

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

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