Android提供另一個非常有用的控制項ViewPager。使用這個控制項,需要用到google提到的一個包——android-support-v4.jar,這個包中包含了一些非常有用的類,其中就是ViewPager類來實現頁面之間的切換操作,關於android-support-v4.jar的詳細資料,大家可以訪問google官方網站:http://developer.android.com/sdk/compatibility-library.html。 具體的把Android提供的android-support-v4.jar匯入工程,並add build path的方法這裡不做介紹,可以參考以上提供的網址,裡面會有詳細的說明,步驟比較簡單。 下面通過兩個例子來講解一下比較複雜的滑動介面的實現。
一、Demo1
Demo1運行效果1 Demo1運行效果2
Demo1實現的效果是我們在瀏覽新聞網頁時經常會看到的,螢幕的上半部分是圖片,下半部分是文字的介紹,而頂部是一個導航的工具列可以供使用者選擇退出或者回到主菜單等。使用者通過左右的滑動螢幕,實現翻頁的效果。而在螢幕的最底部,會有對當前所處頁面的指示標記。
主布局檔案main.xml的內容如下:
xml代碼:
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" > <include android:id="@+id/item_header" layout="@layout/item_header" /> <android.support.v4.view.ViewPager android:id="@+id/myviewpager" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <RelativeLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" > <LinearLayout android:id="@+id/mybottomviewgroup" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_marginBottom="40dp" android:gravity="center_horizontal" android:orientation="horizontal" > </LinearLayout> </RelativeLayout> </LinearLayout></FrameLayout>
最外層是LinearLayout,其中包括兩個Linearlayout,第一個LinearLayout是顯示新聞的主介面,而第二個LinearLayout是為了在底部存放指示當前介面的標記圖片。值得注意的是第一個LinearLayout中包括又包括兩部分,一個是通過include引入的item_header視圖,一個是ViewPager控制項,在這裡還要注意ViewPager空間的布局方式。代碼如下:
xml代碼:
<LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" > <include android:id="@+id/item_header" layout="@layout/item_header" /> <android.support.v4.view.ViewPager android:id="@+id/myviewpager" android:layout_width="fill_parent" android:layout_height="wrap_content" /></LinearLayout>
另外,在layout檔案夾下還定義了item01——item06六個布局檔案作為ViewPager的六個頁面,在JAVA代碼中會把它們分別添加進ViewPager。Item_header.xml布局定義了螢幕上方的導覽列,通過include的方式引入了main.xml布局檔案。
java代碼:
package com.devdiv.test.ui_test_viewpager;import java.util.ArrayList;import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.os.Parcelable;import android.support.v4.view.PagerAdapter;import android.support.v4.view.ViewPager;import android.support.v4.view.ViewPager.OnPageChangeListener;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.ViewGroup.LayoutParams;import android.view.Window;import android.widget.ImageView;public class UI_Test_ViewPagerActivity extends Activity {private ViewPager mViewPager;private ArrayList<View> mPageViews;private ImageView mImageView;private ImageView[] mImageViews;// 該應用的主布局LinearLayoutprivate ViewGroup mainViewGroup;// 主布局底部指示當前頁面的小圓點視圖,LinearLayoutprivate ViewGroup indicatorViewGroup;// 定義LayoutInflaterLayoutInflater mInflater;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// setContentView(R.layout.main);// 設定視窗無標題requestWindowFeature(Window.FEATURE_NO_TITLE);// mInflater = (LayoutInflater)// getSystemService(Context.LAYOUT_INFLATER_SERVICE);mInflater = getLayoutInflater();mPageViews = new ArrayList<View>();mPageViews.add(mInflater.inflate(R.layout.item01, null));mPageViews.add(mInflater.inflate(R.layout.item02, null));mPageViews.add(mInflater.inflate(R.layout.item03, null));mPageViews.add(mInflater.inflate(R.layout.item04, null));mPageViews.add(mInflater.inflate(R.layout.item05, null));mPageViews.add(mInflater.inflate(R.layout.item06, null));mImageViews = new ImageView[mPageViews.size()];mainViewGroup = (ViewGroup) mInflater.inflate(R.layout.main, null);mViewPager = (ViewPager) mainViewGroup.findViewById(R.id.myviewpager);indicatorViewGroup = (ViewGroup) mainViewGroup.findViewById(R.id.mybottomviewgroup);for (int i = 0; i < mImageViews.length; i++) {mImageView = new ImageView(UI_Test_ViewPagerActivity.this);mImageView.setLayoutParams(new LayoutParams(20, 20));mImageView.setPadding(20, 0, 20, 0);if (i == 0) {mImageView.setBackgroundResource(R.drawable.page_indicator_focused);} else {mImageView.setBackgroundResource(R.drawable.page_indicator);}mImageViews[i] = mImageView;// 把指示作用的遠點圖片加入底部的視圖中indicatorViewGroup.addView(mImageViews[i]);}// 注意這兩種用法的區別,前者無法正常顯示!!// setContentView(R.layout.main);setContentView(mainViewGroup);mViewPager.setAdapter(new MyPagerAdapter());mViewPager.setOnPageChangeListener(new OnPageChangeListener() {@Overridepublic void onPageSelected(int arg0) {for (int i = 0; i < mImageViews.length; i++) {if (i == arg0) {mImageViews[i].setBackgroundResource(R.drawable.page_indicator_focused);} else {mImageViews[i].setBackgroundResource(R.drawable.page_indicator);}}}@Overridepublic void onPageScrolled(int arg0, float arg1, int arg2) {}@Overridepublic void onPageScrollStateChanged(int arg0) {}});}class MyPagerAdapter extends PagerAdapter {@Overridepublic int getCount() {return mPageViews.size();}@Overridepublic boolean isViewFromObject(View arg0, Object arg1) {return arg0 == arg1;}@Overridepublic int getItemPosition(Object object) {return super.getItemPosition(object);}@Overridepublic void destroyItem(View arg0, int arg1, Object arg2) {((ViewPager) arg0).removeView(mPageViews.get(arg1));}@Overridepublic Object instantiateItem(View arg0, int arg1) {((ViewPager) arg0).addView(mPageViews.get(arg1));return mPageViews.get(arg1);}@Overridepublic void restoreState(Parcelable arg0, ClassLoader arg1) {}@Overridepublic Parcelable saveState() {return null;}@Overridepublic void startUpdate(View arg0) {}@Overridepublic void finishUpdate(View arg0) {}}}
其中,需要注意的是在自訂MyPagerAdapter繼承自PagerAdapter,需要重寫其中的一些重要方法,可以類比BaseAdapter的實現便於理解,具體實現參考API文檔。
java代碼:
mImageViews = new ImageView[mPageViews.size()]; mainViewGroup = (ViewGroup) mInflater.inflate(R.layout.main, null); mViewPager = (ViewPager) mainViewGroup.findViewById(R.id.myviewpager); indicatorViewGroup = (ViewGroup) mainViewGroup.findViewById(R.id.mybottomviewgroup); for (int i = 0; i < mImageViews.length; i++) { mImageView = new ImageView(UI_Test_ViewPagerActivity.this); mImageView.setLayoutParams(new LayoutParams(20,20)); mImageView.setPadding(20, 0, 20, 0); if (i == 0) { mImageView.setBackgroundResource(R.drawable.page_indicator_focused); } else { mImageView.setBackgroundResource(R.drawable.page_indicator); } mImageViews[i] = mImageView; //把指示作用的遠點圖片加入底部的視圖中 indicatorViewGroup.addView(mImageViews[i]); }
根據mPageViews的大小初始化ImageViews,也就是說ViewPager中存在幾個Page就初始化幾個圓點的圖片進行相應的指示。並且根據位置,設定圓點的不同狀態,出事情況下顯示第一個Page,因此第一個圓點的圖片是focused的狀態。最後,通過indicatorViewGroup.addView(mImageViews[i])把所有圓點的圖片添加到布局中,在螢幕上顯示。
底部圓點圖片初始化並加入布局後,需要給ViewPager設定Adapter,這裡使用的是我們自訂的MyPagerAdapter,然後執行setContentView操作。
最後,為了是底部的圓點視圖具有指示作用,需要為ViewPager設定監聽器,來根據ViewPager的不同狀態,改變底部圓點視圖的狀態。代碼如下:
java代碼:
mViewPager.setOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageSelected(int arg0) { // TODO Auto-generated method stub for (int i = 0; i < mImageViews.length; i++) { if(i == arg0) { mImageViews[i].setBackgroundResource(R.drawable.page_indicator_focused); } else { mImageViews[i].setBackgroundResource(R.drawable.page_indicator); } } } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } @Override public void onPageScrollStateChanged(int arg0) { }});
二、Demo2 Demo2同樣實現了左右滑動的效果,不過我們在不同的頁面使用了不同的布局,這在實際的應用中也是很常見的。我們同樣使用了ViewPager控制項,具體方法和Demo1基本相同。 不同在於,我們在兩個頁面中分別使用了ListView中GridView視圖,並在代碼中為它們分別綁定了不同的Adapter。ListView使用了簡單的ArrayAdapter,顯示一組資料。GridView使用了自訂的Adapter。 由於Demo2和Demo1的內容非常相似,我們就不再展開分析。 Demo2運行效果如下:
第一個視圖 滑動過程中 第二個視圖