ViewPager 詳解(二)---詳解四大函數

前言:上篇中我們講解了如何快速實現了一個滑動頁面,但問題在於,PageAdapter必須要重寫的四個函數,它們都各有什麼意義,在上節的函數內部爲什麼要這麼實現,下面我們就結合android的API說明,詳細講解一下。


相關文章:

1、《ViewPager 詳解(一)---基本入門》

2、《ViewPager 詳解(二)---詳解四大函數》

3、《ViewPager 詳解(三)---PagerTabStrip與PagerTitleStrip添加標題欄的異同》

4、《ViewPager 詳解(四)----自主實現滑動指示條》

5、《ViewPager 詳解(五)-----使用Fragment實現ViewPager滑動》


這篇涉及到內容比較多,因爲有英文文檔和中文文檔,還有示例,在排版上很難駕馭(因爲本人語文太爛……),所以排版有點非常的不賞心悅目,所以只能靠大家耐着性子慢慢看了……,我覺得大家看完之後應該會有所收穫,謝謝。

一、SDK講解

1、官方文檔:(看不懂沒關係,下面有翻譯)

Class Overview


Base class providing the adapter to populate pages inside of a ViewPager. You will most likely want to use a more specific implementation of this, such as FragmentPagerAdapter orFragmentStatePagerAdapter.

When you implement a PagerAdapter, you must override the following methods at minimum:

PagerAdapter is more general than the adapters used for AdapterViews. Instead of providing a View recycling mechanism directly ViewPager uses callbacks to indicate the steps taken during an update. A PagerAdapter may implement a form of View recycling if desired or use a more sophisticated method of managing page Views such as Fragment transactions where each page is represented by its own Fragment.

ViewPager associates each page with a key Object instead of working with Views directly. This key is used to track and uniquely identify a given page independent of its position in the adapter. A call to the PagerAdapter method startUpdate(ViewGroup) indicates that the contents of the ViewPager are about to change. One or more calls to instantiateItem(ViewGroup, int) and/ordestroyItem(ViewGroup, int, Object) will follow, and the end of an update will be signaled by a call to finishUpdate(ViewGroup). By the time finishUpdate returns the views associated with the key objects returned by instantiateItem should be added to the parent ViewGroup passed to these methods and the views associated with the keys passed to destroyItem should be removed. The method isViewFromObject(View, Object) identifies whether a page View is associated with a given key object.

A very simple PagerAdapter may choose to use the page Views themselves as key objects, returning them from instantiateItem(ViewGroup, int) after creation and adding them to the parent ViewGroup. A matching destroyItem(ViewGroup, int, Object) implementation would remove the View from the parent ViewGroup and isViewFromObject(View, Object) could be implemented as return view == object;.

PagerAdapter supports data set changes. Data set changes must occur on the main thread and must end with a call to notifyDataSetChanged() similar to AdapterView adapters derived fromBaseAdapter. A data set change may involve pages being added, removed, or changing position. The ViewPager will keep the current page active provided the adapter implements the methodgetItemPosition(Object).

網址:http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html

2、對應翻譯

Class Overview


提供一個適配器用於填充ViewPager頁面. 你很可能想要使用一個更加具體的實現, 例如: FragmentPagerAdapter or FragmentStatePagerAdapter.

當你實現一個PagerAdapter時,至少需要覆蓋以下幾個方法:

PagerAdapter比AdapterView的使用更加普通.ViewPager使用回調函數來表示一個更新的步驟,而不是使用一個視圖回收機制。在需要的時候pageradapter也可以實現視圖的回收或者使用一種更爲巧妙的方法來管理視圖,比如採用可以管理自身視圖的fragment。

viewpager不直接處理每一個視圖而是將各個視圖與一個鍵聯繫起來。這個鍵用來跟蹤且唯一代表一個頁面,不僅如此,該鍵還獨立於這個頁面所在adapter的位置。當pageradapter將要改變的時候他會調用startUpdate函數,接下來會調用一次或多次的instantiateItem或者destroyItem。最後在更新的後期會調用finishUpdate。當finishUpdate返回時 instantiateItem返回的對象應該添加到父ViewGroup destroyItem返回的對象應該被ViewGroup刪除。methodisViewFromObject(View, Object)代表了當前的頁面是否與給定的鍵相關聯。
 
對於非常簡單的pageradapter或許你可以選擇用page本身作爲鍵,在創建並且添加到viewgroup後instantiateItem方法裏返回該page本身即可
destroyItem將會將該page從viewgroup裏面移除。isViewFromObject方法裏面直接可以返回view == object。
 
pageradapter支持數據集合的改變,數據集合的改變必須要在主線程裏面執行,然後還要調用notifyDataSetChanged方法。和baseadapter非常相似。數據集合的改變包括頁面的添加刪除和修改位置。viewpager要維持當前頁面是活動的,所以你必須提供getItemPosition方法。

網址:http://www.cnblogs.com/tony-yang-flutter/p/3591825.html

3、解析

看上面的翻譯,與我們相關只有這兩段話:

viewpager不直接處理每一個視圖而是將各個視圖與一個鍵聯繫起來。這個鍵用來跟蹤且唯一代表一個頁面,不僅如此,該鍵還獨立於這個頁面所在adapter的位置。當pageradapter將要改變的時候他會調用startUpdate函數,接下來會調用一次或多次的instantiateItem或者destroyItem。最後在更新的後期會調用finishUpdate。當finishUpdate返回時 instantiateItem返回的對象應該添加到父ViewGroup destroyItem返回的對象應該被ViewGroup刪除。methodisViewFromObject(View, Object)代表了當前的頁面是否與給定的鍵相關聯。

對於非常簡單的pageradapter或許你可以選擇用page本身作爲鍵,在創建並且添加到viewgroup後instantiateItem方法裏返回該page本身即可destroyItem將會將該page從viewgroup裏面移除。isViewFromObject方法裏面直接可以返回view == object。

對於上面兩段話,我這裏有兩點要着重講一下:

1、第一段說明了,鍵(Key)的概念,首先這裏要清楚的一點是,每個滑動頁面都對應一個Key,而且這個Key值是用來唯一追蹤這個頁面的,也就是說每個滑動頁面都與一個唯一的Key一一對應。大家先有這個概念就好,關於這個Key是怎麼來的,下面再講。

2、第二段簡單講了一個應用,即將當前頁面本身的View作爲Key。其實這個應用就是我們前一章講的例子應用。不太理解?沒關係,下面細講。下面我們講講Key的問題

4、關於Key

現在我帶着大家看看幾個方法的官方文檔:(這裏結合《ViewPager 詳解(一)---基本入門》最底部的例子來看)

首先:destroyItem()

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

Remove a page for the given position. The adapter is responsible for removing the view from its container, although it only must ensure this is done by the time it returns fromfinishUpdate(ViewGroup).

Parameters
container The containing View from which the page will be removed.
position The page position to be removed.
object The same object that was returned by instantiateItem(View, int).

該方法實現的功能是移除一個給定位置的頁面。適配器有責任從容器中刪除這個視圖。這是爲了確保在finishUpdate(viewGroup)返回時視圖能夠被移除。

下面看看《ViewPager 詳解(一)---基本入門》中是如何做的:

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. @Override  
  2. public void destroyItem(ViewGroup container, int position,  
  3.         Object object) {  
  4.     // TODO Auto-generated method stub  
  5.     container.removeView(viewList.get(position));  
  6. }  
果不其然,我們將給定位置的視圖從container中移除了……

然後看getCount ()

public abstract int getCount ()

Return the number of views available.

返回當前有效視圖的個數。

在上一章例子中,我們是這麼做的:

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. @Override  
  2. public int getCount() {  
  3.     // TODO Auto-generated method stub  
  4.     return viewList.size();  
  5. }  
返回了當前要滑動視圖的個數,與SDK說明一致。

最難的兩個來了

instantiateItem (ViewGroup container, int position)

public Object instantiateItem (ViewGroup container, int position)

Create the page for the given position. The adapter is responsible for adding the view to the container given here, although it only must ensure this is done by the time it returns fromfinishUpdate(ViewGroup).

Parameters
container The containing View in which the page will be shown.
position The page position to be instantiated.
Returns
  • Returns an Object representing the new page. This does not need to be a View, but can be some other container of the page.
這個函數的實現的功能是創建指定位置的頁面視圖。適配器有責任增加即將創建的View視圖到這裏給定的container中,這是爲了確保在finishUpdate(viewGroup)返回時this is be done!

返回值:返回一個代表新增視圖頁面的Object(Key),這裏沒必要非要返回視圖本身,也可以這個頁面的其它容器。其實我的理解是可以代表當前頁面的任意值,只要你可以與你增加的View一一對應即可,比如position變量也可以做爲Key(最後我們舉個例子試試可不可行)

心得 :

1、從說明中可以看到,在代碼中,我們的責任是將指定position的視圖添加到conatiner中

2、Key的問題:從這個函數就可以看出,該函數返回值就是我們根據參數position增加到conatiner裏的View的所對應的Key!!!!!!!

3、“it only must ensure this is done by the time it returns fromfinishUpdate(ViewGroup).”這句話在destroyItem()的函數說明中同樣出現過,這說明在 finishUpdate(viewGroup)執行完後,有兩個操作,一個是原視圖的移除(不再顯示的視圖),另一個是新增顯示視圖(即將顯示的視圖)

在上一章的代碼中,我們是這樣做的:

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. @Override  
  2. public Object instantiateItem(ViewGroup container, int position) {  
  3.     // TODO Auto-generated method stub  
  4.         container.addView(viewList.get(position));  
  5.           
  6.           
  7.         return viewList.get(position);  
  8.     }  
  9. };  
在這裏,我們做了兩件事

第一:將參數裏給定的position的視圖,增加到conatiner中,供其創建並顯示、。

第二:返回當前position的View做爲此視圖的Key。還記得API官方文檔中下面這段話麼?
對於非常簡單的pageradapter或許你可以選擇用page本身作爲鍵,在創建並且添加到viewgroup後instantiateItem方法裏返回該page本身即可destroyItem將會將該page從viewgroup裏面移除。isViewFromObject方法裏面直接可以返回view == object。

這裏就把當前的View當作Key傳過出去!!!!

最後一個: isViewFromObject (View view, Object object)

public abstract boolean isViewFromObject (View view, Object object)

Determines whether a page View is associated with a specific key object as returned by instantiateItem(ViewGroup, int). This method is required for a PagerAdapter to function properly.

Parameters
view Page View to check for association with object
object Object to check for association with view
Returns
  • true if view is associated with the key object object
功能:該函數用來判斷instantiateItem(ViewGroup, int)函數所返回來的Key與一個頁面視圖是否是代表的同一個視圖(即它倆是否是對應的,對應的表示同一個View)

返回值:如果對應的是同一個View,返回True,否則返回False。

在上章節的例子中,我們這樣做的:

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. @Override  
  2. public boolean isViewFromObject(View arg0, Object arg1) {  
  3.     // TODO Auto-generated method stub  
  4.     return arg0 == arg1;  
  5. }  
由於在instantiateItem()中,我們作爲Key返回來的是當前的View,所以在這裏判斷時,我們直接將Key與View看是否相等來判斷是否是同一個View。

二、自定義Key實例

經過上面的講解,想必大家給Key的概念應該有個清楚的理解,下面舉個例子來說明Key與View的關係,由於Key與View要一一對應,所以我把每個視圖所處的位置Position作爲Key,在上章例子的基礎上更改的,下面先看全部代碼,然後看部分講解:

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. package com.example.testviewpage_2;  
  2. /** 
  3.  * @author  harvic 
  4.  * @date 2014.8.11 
  5.  */  
  6. import java.util.ArrayList;  
  7. import java.util.List;  
  8. import android.app.Activity;  
  9. import android.os.Bundle;  
  10. import android.support.v4.view.PagerAdapter;  
  11. import android.support.v4.view.ViewPager;  
  12. import android.view.LayoutInflater;  
  13. import android.view.View;  
  14. import android.view.ViewGroup;  
  15.   
  16. public class MainActivity extends Activity {  
  17.   
  18.     private View view1, view2, view3;  
  19.     private List<View> viewList;// view數組  
  20.     private ViewPager viewPager; // 對應的viewPager  
  21.       
  22.     @Override  
  23.     protected void onCreate(Bundle savedInstanceState) {  
  24.         super.onCreate(savedInstanceState);  
  25.         setContentView(R.layout.activity_main);  
  26.         viewPager = (ViewPager) findViewById(R.id.viewpager);  
  27.         LayoutInflater inflater = getLayoutInflater();  
  28.         view1 = inflater.inflate(R.layout.layout1, null);  
  29.         view2 = inflater.inflate(R.layout.layout2, null);  
  30.         view3 = inflater.inflate(R.layout.layout3, null);  
  31.   
  32.         viewList = new ArrayList<View>();// 將要分頁顯示的View裝入數組中  
  33.         viewList.add(view1);  
  34.         viewList.add(view2);  
  35.         viewList.add(view3);  
  36.   
  37.         PagerAdapter pagerAdapter = new PagerAdapter() {  
  38.   
  39.             @Override  
  40.             public boolean isViewFromObject(View arg0, Object arg1) {  
  41.                 // TODO Auto-generated method stub  
  42.                 //根據傳來的key,找到view,判斷與傳來的參數View arg0是不是同一個視圖  
  43.                 return arg0 == viewList.get((int)Integer.parseInt(arg1.toString()));  
  44.             }  
  45.   
  46.             @Override  
  47.             public int getCount() {  
  48.                 // TODO Auto-generated method stub  
  49.                 return viewList.size();  
  50.             }  
  51.   
  52.             @Override  
  53.             public void destroyItem(ViewGroup container, int position,  
  54.                     Object object) {  
  55.                 // TODO Auto-generated method stub  
  56.                 container.removeView(viewList.get(position));  
  57.             }  
  58.   
  59.             @Override  
  60.             public Object instantiateItem(ViewGroup container, int position) {  
  61.                 // TODO Auto-generated method stub  
  62.                 container.addView(viewList.get(position));  
  63.   
  64.                 //把當前新增視圖的位置(position)作爲Key傳過去  
  65.                 return position;  
  66.             }  
  67.         };  
  68.   
  69.         viewPager.setAdapter(pagerAdapter);  
  70.   
  71.     }  
  72.   
  73. }  
在這裏更改了兩個地方:

1、先看Key的產生的位置instantiateItem()

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. @Override  
  2. public Object instantiateItem(ViewGroup container, int position) {  
  3.     // TODO Auto-generated method stub  
  4.     container.addView(viewList.get(position));  
  5.   
  6.     //把當前新增視圖的位置(position)作爲Key傳過去  
  7.     return position;  
  8. }  

我們在上講也講了在這個函數中Key是作爲返回值與當前裝入Container中的視圖對應起來的。所以在這裏我們返回postion與container.addView(viewList.get(position));裏的viewList.get(position)這個視圖對應起來。
2、isViewFromObject ()

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. @Override  
  2. public boolean isViewFromObject(View arg0, Object arg1) {  
  3.     // TODO Auto-generated method stub  
  4.     //根據傳來的key,找到view,判斷與傳來的參數View arg0是不是同一個視圖  
  5.     return arg0 == viewList.get((int)Integer.parseInt(arg1.toString()));  
  6. }  

判斷從instantiateItem()返回來的Key與當前的View是否能對應起來,我們知道從instantiateItem傳過來的其實是position,所以我們要根據position找到View,然後跟參數中的View arg0判斷。

但在真正操作時出現了問題,我們要先將obect對應轉換爲int類型:(int)Integer.parseInt(arg1.toString());然後再根據position找到對應的View;

效果圖:三個View之間的滑動切換

  

這裏只所以與上章不一樣,僅僅只有上部分一部分的地方纔有滑動切換,是因爲我更改了佈局文件:

[html] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     tools:context="com.example.testviewpage_2.MainActivity" >  
  6.   
  7.     <android.support.v4.view.ViewPager  
  8.         android:id="@+id/viewpager"  
  9.         android:layout_width="wrap_content"  
  10.         android:layout_height="200dip"  
  11.         android:layout_gravity="center" />  
  12.   
  13. </RelativeLayout>  
這裏將layout_height更改爲200dip,只所以這麼做,是爲了告訴大家,只要在想要實現滑動切換的地方添加上<android.support.v4.view.ViewPager />就可以實現切換,無所謂位置和大小,跟普通控件一樣!!!!!!

源碼地址:http://download.csdn.net/detail/harvic880925/7739873


請大家尊重原創者版權,轉載請標明出處:http://blog.csdn.net/harvic880925/article/details/38487149   萬分感激!!!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章