天天看點

Android開發之ViewPager使用詳解(一)

   ViewPager在開發中用的還是比較多的,比方說一些引導頁,應用的主界面,最近也是用到了好多次,于是就系統的學習了下,那麼今天就來和大家一起來分享下ViewPager的用法,如有謬誤歡迎批評指正,如有疑問歡迎留言。

通過本篇部落格你将學到以下知識點:

①ViewPager的用法

②PagerAdapter的四個函數的用法(詳細)

1、ViewPager的用法介紹

首先我們來看看ViewPager是什麼東西?看看它的繼承關系圖

Android開發之ViewPager使用詳解(一)

從繼承圖中我們可以看到它是繼承自ViewGroup的,是一個容器,那麼它應該怎麼用呢?首先來引用官方文檔的一段話: 布局管理器允許使用者左右翻轉頁面的資料,你可以提供一個PagerAdapter來生成要顯示的視圖,ViewPager經常和Fragment一起使用,這樣就可以很友善的提供和管理每一個界面的生命周期,有标準的擴充卡的實作方式用于使用Fragment的ViewPager,這樣的擴充卡包含了最常見的案例,它就是FragmentPagerAdapter和FragmentStatePagerAdapter,這兩個擴充卡都是簡單的代碼來示範如何建構一個完整的使用者界面。

從官方給我們的介紹可以看出要想使用ViewPager首先要做的就是得給它一個擴充卡(這點跟ListView類似),它經常和Fragment一起使用(這個用法後面文正再講),首先來學習PagerAdapter的用法,這也是今天的重點。 跟ViewPager一樣首先來看看它的繼承關系圖

Android開發之ViewPager使用詳解(一)

從圖中看出PagerAdapter是support.v4下的一個類,它的直接子類有FragmentPagerAdapter和FragmentStatePagerAdapter。首先我們需要知道的是在繼承PagerAdapter時必須要實作它的四個函數(這一點官方文檔,以及方法的說明都可以看到),我在這裡截個圖給大家看一下

Android開發之ViewPager使用詳解(一)

看到了吧,上面紅框内的四個函數就是必須要重寫的函數,那麼它是怎麼運作呢?再來看官方文檔的一段關于PagerAdapter話: 第一段話的翻譯

ViewPager将每一個頁面與一個Key對象進行關聯,而不是直接操作這個視圖,這個Key對象用來跟蹤和唯一的辨別一個給定的視圖,獨立于擴充卡中的位置,調用PagerAdapter的startUpdate(ViewGroup)方法表明ViewPager的内容将要發生變化,接着一次或多次的調用instantiateItem(ViewGroup,int)和destroyItem(ViewGroup,int,Object)方法,通過調用finishUpdate(ViewGroup)來辨別更新的完成,finishUpdate方法傳回一個視圖,這個視圖和一個Key對象相關聯,這個Key對象是instantiateItem的傳回值,這個視圖應該添加到父ViewGroup,傳遞給這些方法并且這個和Key相關的的視圖會傳遞到destroyItem方法中,在這個方法中會将這個視圖移除。方法isViewFromObject(View,Object)用于辨別一個視圖是否和給定的Key對象相關。

一個簡單的PagerAdapter可以選擇用視圖本身做為Key對象,在視圖建立并加入到父ViewGroup後通過instantiateItem(ViewGroup,int)方法将此視圖傳回。在destroyItem(ViewGroup,int,Object)這個方法中将會從父ViewGroup中将這個視圖删除,而isViewFromObject(View,Object)可以這樣實作:return view==object。

哎呦,我以後要努力學英語了。。。。

2、詳解PagerAdapter的四大函數

       從谷歌官方給出的文檔中,可以看到ViewPager并不是直接操作每一個視圖的本身,而是将各個視圖與一個Key對象關聯起來(這有點類似于Map),這個Key對象就和這個視圖一一對應,并且這個Key對象就是instatiateItem(ViewGroup,int)這個方法的傳回值。在最後谷歌給了我們建議,它建議我們将視圖本身作為傳回值,然後在isViewFromObject(View,Object)中直接 retutn view==object;看到這裡肯定會有好多人雲裡霧裡,這裡稍微難了解一點的就是這個Key,不要着急我将通過一個小例子來專門講解這個Key,還廢什麼話,接着我們通過兩個執行個體來詳細講解PagerAdapter的用法,相信你看完後會了解PagerAdapter的用法,這個例子很簡單,就是将幾張圖檔添加到界面,這些界面可以左右滑動,效果圖如下

Android開發之ViewPager使用詳解(一)

首先來看下這裡的PagerAdapter是怎麼寫的

package com.example.viewpagertest.adapter;

import java.util.List;

import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;


public class MyAdapter extends PagerAdapter {
     
     private Context mContext;
     private List<View> mViewList;
     
     public MyAdapter(Context context, List<View> viewList){
            this. mContext=context;
            this. mViewList=viewList;
     }

     @Override
     public Object instantiateItem(ViewGroup container, int position) {

           container.addView( mViewList.get(position));
            return mViewList.get(position);
     }

     @Override
     public void destroyItem(ViewGroup container, int position, Object object) {
           
           container.removeView( mViewList.get(position));
     }

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

     @Override
     public boolean isViewFromObject(View view, Object object) {
            //當傳回為true的時候,就将根據目前的position得到的view展示出來
            return view== object;
     }
}
           

對PagerAdapter的這四個函數我将比對着谷歌文檔來進行講解

2.1 getCount方法

getCount方法的官方文檔說明

傳回視圖的個數,這個方法很簡單沒什麼可說的,在上面的例子中我們是這樣做的

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

即将存放View的一個集合的大小傳回,這裡的大小也就是視圖的個數

2.2 instantiateItem方法

instantiateItem方法的官方文檔說明

這個方法的主要作用就是根據目前的posistion來建立對應的視圖,并且将這個建立好的視圖添加到容器中,這個添加操作是在調用

finishUpdate(ViewGroup)這個方法之前完成的。

instantiateItem 方法會傳回一個對象,這個對象代表這一個新的視圖,這個對象不一定是一個View,可以是這個視圖的其他容器,也就是說隻要可以唯一代表這個界面的東西都可以作為這個對象。 在上述例子中我們是這樣實作的

@Override
      public Object instantiateItem(ViewGroup container, int position) {

           container.addView( mViewList.get(position));
            return mViewList.get(position);
     }
           

将mViewList中的一個View取出來,添加到視圖中,然後将這個視圖傳回,這裡也是按照谷歌的建議來寫的。此時這個return的mViewList.get(position)就和這個添加到containter的View對應了起來。

2.3 isViewFromObject方法

這個方法的作用就是用來判斷 

instantiateItem(ViewGroup, int)方法傳回的Key是否和界面的View相關聯,如果關聯則傳回true,否則傳回false。關于傳回true和傳回false的差別谷歌官方文檔沒有說明,看了好多資料最後在stackoverflow上找到了答案,這裡把這個連結的位址貼出來:

http://stackoverflow.com/questions/30995446/what-is-the-role-of-isviewfromobject-view-view-object-object-in-fragmentst 當傳回為true時 就将根據目前的position得到的view展示出來,否則就不展示。這裡可以直接傳回false發現viewpager一個界面也沒有,直接傳回true可以看到重合的界面,大家去自己去試試。 在上面的例子中我們是這麼寫的

@Override
     public boolean isViewFromObject(View view, Object object) {
            //當傳回為true的時候,就将根據目前的position得到的view展示出來
            return view==object;
     }
           

這也是谷歌建議的方式,這裡的view就是目前要展示的界面,這裡的object就是 instantiateItem方法的傳回值,因為在 instantiateItem方法中傳回了這個界面是以這裡view==object是為true的。

2.4 destroyItem方法

這個方法的作用就是從容器中移除position所對應的視圖,而且這個移除的動作是在finishUpdate之前完成的。這個在 instantiateItem 方法中也提到過,也就是說在finishUpdate之前至少要完成兩個動作①原來視圖的移除②新視圖的增加 在上面的例子我們是這麼做的

@Override
     public void destroyItem(ViewGroup container, int position, Object object) {
           
           container.removeView( mViewList.get(position));
     }
           

即根據position移除它所對應的界面。

到這裡PagerAdapter的四個方法就介紹完了,看完後大家可能對Key這個概念有點模糊,沒關系,接下來我們不按照谷歌給我們的建議即不将View本身作為 instantiateItem方法的傳回值。

3、深入了解Key的兩個案例 從instantiateItem的方法介紹能夠看到能夠作為Key不僅僅是View本身也可以是其它的。那麼我們就來兩個自定義的Key的例子,這兩個例子也非常簡單就是對上面的代碼做簡單的修改,其它的内容不變隻修改PagerAdapter的内容。

案例一 對上述例子中的MyAdapter修改後的代碼如下

package com.example.viewpagertest.adapter;

import java.util.List;

import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;


public class MyAdapter extends PagerAdapter {
     
     private Context mContext;
     private List<View> mViewList;
     
     public MyAdapter(Context context, List<View> viewList){
            this. mContext=context;
            this. mViewList=viewList;
     }

     @Override
     public Object instantiateItem(ViewGroup container, int position) {

           container.addView( mViewList.get(position));
            return position;
     }

     @Override
     public void destroyItem(ViewGroup container, int position, Object object) {
           
           container.removeView( mViewList.get(position));
     }

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

     @Override
     public boolean isViewFromObject(View view, Object object) {
            //當傳回為true的時候,就将根據目前的position得到的view展示出來
            return view==mViewList.get(Integer.parseInt(object.toString()));
     }
}
           

這裡隻是将 instantiateItem方法的傳回值由 mViewList .get(position)變成了position,然後将 isViewFromObject方法的傳回值由 view==  object改為了 view== mViewList  .get(Integer.parseInt(object.toString())),然後運作程式你會發現和之前的效果一樣,這裡的 instantiateItem方法将position傳回然後在 isViewFromObject方法中根據這個position找到View然後判斷是否相等,進而決定這個position的View是否展示出來。

案例二

package com.example.viewpagertest.adapter;

import java.util.ArrayList;
import java.util.List;

import com.example.viewpagertest.R;

import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;


public class MyAdapter extends PagerAdapter {
     
     private Context mContext;
     private List<View> mViewList;
     private List<Integer> mList;
     
     public MyAdapter(Context context, List<View> viewList){
            this. mContext=context;
            this. mViewList=viewList;
           
            mList= new ArrayList<Integer>();
     }

     @Override
     public Object instantiateItem(ViewGroup container, int position) {

           View view = mViewList.get(position);
           container.addView(view);
           
           ImageView iv = (ImageView) view.findViewById(R.id.iv_test );
  
            return iv;
     }

     @Override
     public void destroyItem(ViewGroup container, int position, Object object) {
           
           container.removeView( mViewList.get(position));
     }

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

     @Override
     public boolean isViewFromObject(View view, Object object) {
            //當傳回為true的時候,就将根據目前的position得到的view展示出來
           ImageView iv =(ImageView) view.findViewById(R.id.iv_test );
           
            return iv==object;
     }
}
           

這次我們也是做了兩處修改,這裡在 instantiateItem這個方法中傳回目前View中的ImageView對象,讓ImageView對象作為标志這個界面的Key,而在isViewFromObject 這個方法中通過view查找出ImageView然後判斷這兩個ImageView是不是同一個View中的ImageView如果是就顯示,否則不顯示。到這裡相信大家對Key這個概念應該有了清楚的認識。

好了,到這裡關于ViewPager的pagerAdapter的用法就介紹完了,後面會繼續給大家帶來FragmentPagerAdapter等,關于ViewPager的知識,不知道大家還有沒有什麼疑問,如果大家發現本文中有錯誤,或者有什麼疑問歡迎批評指正,大家共同進步,謝謝。。。

如果你覺着本文對你有幫助我絕對不介意你頂一下,贊一個,哈哈。。。。

部落格中源碼點這裡