在Android開發中,使用ViewPager控件可以輕松實現多個頁面的滑動顯示效果。需要注意的一點是,在Android3.0版本的SDK之后提供了android-support-v4.jar包,用於實現版本的兼容,讓老版本系統下的應用通過加載這個包實現擴展。所以在使用ViewPager控件時,可以根據需要往工程中導入android-support-v4.jar包。
在本篇博文中,我將以一個簡單的例子演示如何使用ViewPager控件實現滑屏顯示效果。完成后的運行效果如圖1所示。
圖1 ViewPager效果圖
(說明:圖1中所示新聞圖片來自鳳凰網和騰訊網,特此說明。)
在該實例中,我制作了一個類似新聞導航功能的UI界面,頂端有四個選項卡“首頁”、“新聞”、“娛樂”以及“博客”,每個選項卡的下面會顯示與之相應的選項內容(該實例主要是為了學習ViewPager控件的使用,所以目前只實現了“新聞”選項卡下面的內容)。在“新聞”選項內,使用ViewPager控件實現了三條新聞的滑動顯示效果,通過左右拖動頁面可以進行頁面的切換,同時,在頁面的下方還實現了一個頁面指示器,可以告訴用戶總共可以滑動幾屏,以及當前頁面所處的位置是第幾屏。
下面就來詳細說說這個實例的具體實現過程。
1.主界面設計
由圖1可以看出,該實例的主界面是由四部分組成的:頂端的導航條、新聞圖片、新聞正文概要、底端的頁面指示器。
主界面布局使用FrameLayout作為主布局格式,目的在於當ViewPager控件左右滑動顯示不同的新聞內容時,頂端的導航條和底端的頁面指示器不受影響,而顯示在最上層。
具體的主界面布局源代碼如下:
1 <FrameLayout 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 6 <!-- 頂端導航欄 --> 7 <include 8 layout="@layout/layout_include"/> 9 10 <!-- 滑屏界面 --> 11 <android.support.v4.view.ViewPager 12 android:id="@+id/viewpager" 13 android:layout_width="wrap_content" 14 android:layout_height="wrap_content" 15 android:layout_marginTop="34dp" 16 android:layout_gravity="center" > 17 <!-- 18 <android.support.v4.view.PagerTitleStrip 19 android:id="@+id/viewpagetitle" 20 android:layout_width="wrap_content" 21 android:layout_height="wrap_content" 22 android:layout_gravity="top" > 23 </android.support.v4.view.PagerTitleStrip> 24 --> 25 </android.support.v4.view.ViewPager> 26 27 <!-- 底端的頁面指示器 --> 28 <RelativeLayout 29 android:layout_width="match_parent" 30 android:layout_height="wrap_content" > 31 <LinearLayout 32 android:id="@+id/page_indicator" 33 android:layout_width="match_parent" 34 android:layout_height="wrap_content" 35 android:orientation="horizontal" 36 android:gravity="center_horizontal" 37 android:layout_marginTop="400dp" > 38 </LinearLayout> 39 </RelativeLayout> 40 </FrameLayout>
其中,主界面中有關導航欄的控件布局定義在了xml文件layout_include.xml中,然后,通過使用了<include></include>標簽將導航欄的布局文件靜態的加載到了主界面布局中來,使主界面的布局文件結構更加清晰,同時也便於代碼維護。
有關靜態布局文件的加載可以參看《Android學習筆記31:使用惰性控件ViewStub實現布局動態加載》(http://www.cnblogs.com/menlsh/archive/2013/03/17/2965217.html)。
有一點需要注意,ViewPager控件的xml標簽和普通的Android控件標簽不太一樣,需要使用<android.support.v4.view.ViewPager></android.support.v4.view.ViewPager>的形式,將包名也包含其中。並且,ViewPager控件還提供了一個內嵌的滑屏標題控件<android.support.v4.view.PagerTitleStrip></android.support.v4.view.PagerTitleStrip>,可以用於設置每一屏的標題。在該實例中,並未使用該控件,所以將其注釋掉了。
此外,在主界面布局文件的最后,定義了一個水平的線性布局LinearLayout,用來動態的加載頁面指示器。
至此,該實例的主界面就設計好了。
2.ViewPager界面設計
在該實例中,有3張不同的ViewPager界面,每張ViewPager界面都是有兩部分構成的:新聞圖片和新聞正文概要。當然了,每張ViewPager界面顯示的內容都是不同的,所以需要分別進行布局設計。
在本實例中,每張ViewPager界面布局的格式都是一樣的,使用垂直線性布局LinearLayout將ViewPager界面划分為兩部分,上部分使用ImageView控件顯示新聞圖片,下部分使用TextView顯示新聞正文概要。
該實例中的第一條新聞報道的ViewPager界面布局源代碼如下:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="wrap_content" 5 android:orientation="vertical" > 6 7 <ImageView 8 android:layout_width="match_parent" 9 android:layout_height="wrap_content" 10 android:scaleType="center" 11 android:src="@drawable/visitor" /> 12 <TextView 13 android:layout_width="match_parent" 14 android:layout_height="wrap_content" 15 android:layout_marginTop="5dp" 16 android:layout_marginLeft="20dp" 17 android:layout_marginRight="20dp" 18 android:text="@string/news_content_one" /> 19 20 </LinearLayout>
其它兩張ViewPager界面的布局文件和如上的代碼大同小異,這里就不再贅述了。我將這3張ViewPager界面的布局文件分別命名為了“layout_news_one”、“layout_news_two”、“layout_news_three”,在PagerAdapter中需要加載這3個xml文件。
3.頁面適配器PagerAdapter
如何加載每一屏的內容到ViewPager控件中呢?答案是使用頁面適配器PagerAdapter。
PagerAdapter是一個抽象類,在繼承PagerAdapter類時,必須要實現PagerAdapter類的四個抽象方法:
(1)public Object instantiateItem (ViewGroup container, int position);
(2)public void destroyItem (ViewGroup container, int position, Object object);
(3)public abstract int getCount ();
(4)public abstract boolean isViewFromObject (View view, Object object);
其中,instantiateItem()方法的作用是初始化ViewPager中的項;destroyItem()方法的作用是銷毀ViewPager中的項;getCount()方法的作用是獲取ViewPager中有多少項(有幾屏);isViewFromObject()方法的作用是判斷是否由對象生成界面。
在該實例中,新建了一個繼承自PagerAdapter的MyPagerAdapter類,並實現了以上的抽象方法。該類的具體實現如下:
1 package com.example.android_viewpager; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import android.content.Context; 7 import android.support.v4.view.PagerAdapter; 8 import android.support.v4.view.ViewPager; 9 import android.view.LayoutInflater; 10 import android.view.View; 11 12 public class MyPagerAdapter extends PagerAdapter { 13 14 List<View> mListViewPager; //ViewPager對象的內容 15 List<String> mListViewPagerTitle; //ViewPager對象的標題(未使用) 16 Context mContext; 17 18 public MyPagerAdapter(Context Context) { 19 this.mContext = Context; 20 21 //加載xml文件到ViewPager對象中 22 View viewPagerNews1 = LayoutInflater.from(mContext).inflate(R.layout.layout_news_one, null); 23 View viewPagerNews2 = LayoutInflater.from(mContext).inflate(R.layout.layout_news_two, null); 24 View viewPagerNews3 = LayoutInflater.from(mContext).inflate(R.layout.layout_news_three, null); 25 mListViewPager = new ArrayList<View>(); 26 mListViewPager.add(viewPagerNews1); 27 mListViewPager.add(viewPagerNews2); 28 mListViewPager.add(viewPagerNews3); 29 } 30 31 //獲取ViewPager的頁數 32 public int getCount() { 33 return mListViewPager.size(); 34 } 35 36 //初始化ViewPager中的項 37 public Object instantiateItem(View container, int position) { 38 ((ViewPager)container).addView(mListViewPager.get(position)); 39 return mListViewPager.get(position); 40 } 41 42 //獲取每個ViewPager的標題 43 public CharSequence getPageTitle(int position) { 44 return mListViewPagerTitle.get(position); 45 } 46 47 //判斷是否由對象生成界面 48 public boolean isViewFromObject(View view, Object object) { 49 return view == object; 50 } 51 52 //銷毀ViewPager中的項 53 public void destroyItem(View container, int position, Object object) { 54 ((ViewPager)container).removeView(mListViewPager.get(position)); 55 } 56 }
此外,還需要使用ViewPager類的setAdapter (PagerAdapter adapter)方法加載該自定義的MyPagerAdapter適配器。
4.ViewPager事件監聽
在該實例中,我們需要對ViewPager進行事件監聽,以便實現底端的頁面指示器功能。
要實現ViewPager的事件監聽,我們可以根據需要實現OnPageChangeListener接口中的以下3個事件監聽處理方法:
(1)public abstract void onPageScrollStateChanged (int state);
(2)public abstract void onPageScrolled (int position, float positionOffset, int positionOffsetPixels);
(3)public abstract void onPageSelected (int position);
這3個方法的調用時機各不一樣。其中,onPageScrollStateChanged()方法發生在滾動狀態變化時,用於監測用戶開始拖動ViewPager;onPageScrolled()方法發生在當前頁面滾動時,用於監測用於拖動當前頁面的程度(偏移量多少);onPageSelected()方法發生在當前頁面被選擇時,用於監測當前滑動到了哪一個頁面。
顯然,要實現底端的頁面指示器功能,我們需要實現onPageSelected()方法。實現方法如下:
1 /* 2 * Function : 事件監聽處理 3 * Author : 博客園-依舊淡然 4 */ 5 public void onPageSelected(int position) { 6 for(int i = 0; i < myPagerAdapter.getCount(); i++) { 7 if(position == i) { 8 mIndicatorList[position].setBackgroundResource(R.drawable.page_indicator_big); 9 } else { 10 mIndicatorList[i].setBackgroundResource(R.drawable.page_indicator_small); 11 } 12 } 13 }
通過以上的方法,我們便實現了底端的頁面指示器功能,讓當前的顯示頁面在指示器中以大圓圈表示。