スワイプ動作でページ送りする(ViewPager)


ViewPagerを使うとページ送りを簡単に実装することが出来ます。
ViewPagerは左右にページ送りできます。またアニメーションがつくので非常にわかりやすく、直感的なUIを提供できる機能です。
便利な機能ですが、2011/9/29時点ではAndroid SDKに含まれておらず、Android Compatibility package, revision 3(外部ライブラリー)として提供されています。
今回は、この外部ライブラリーの追加から実際のサンプルコードが動作するまでを紹介します。ポイントは次の2点です。

  • 外部ライブラリ「Android Compatibility package, revision 3」の導入
  • ViewPagerをつかうためにはPagerAdapterが必要

ごく簡単に言えば、ViewPagerは入れ物です。表示する内容(ギャラリーアプリであれば写真、動画など)はPagerAdapter経由でViewPagerに指示することになります。
それでは、外部ライブラリの導入からソースコードの解説まで順番に確認していきましょう。

外部ライブラリの導入

「Android Compatibility package, revision 3」はAndroid SDKおよびADVマネージャーからインストールできます。
コンパチビリティパッケージは fragmentの紹介記事 “Compatibility Package を使って、FragmentをHoneyComb以外で利用する”でもインストール方法を紹介しています(こちらはMac)。

Available packages一覧からダウンロードしてください。成功するとInstalled packagesに「Android Compatibility package, revision 3」が表示されます。

ダウンロードした外部ライブラリは以下に格納されています。

android-sdk-windows/extras/android/compatibility/

compatibilityディレクトリ以下にはv4(Android3.2未満)およびv13(Android3.2以降)と、環境にあわせてディレクトリが用意されています。プロジェクトにのターゲットAPIに応じて配置してください。

プロジェクトへのコピー例

  1. プロジェクトのルート以下にlibsディレクトリを作成
  2. android-sdk-windows/extras/android/compatibility/v4/
  3. プロジェクトのルート/libs/android-support-v4.jarをコピー

(v4を利用する場合。Android 3.2以降はv13で読み替えてください)
compatibilityディレクトリ以下にREADME/NOTICEテキストが用意されています。注意点、機能などが紹介されていますので、読んでみると良いかもしれません。

Eclipseでの設定

続いてダウンロードした外部ライブラリをプロジェクトへ追加しましょう。
Eclipseで追加したいプロジェクトを開いてください。プロジェクトのプロパティで設定できます。
手順は以下の通りです。

Eclipseメニュー>プロジェクト>プロパティ
Javaのビルド・パス>ライブラリタブを選択>「外部Jar追加」ボタン
先ほどコピーしたjarファイルを選択


メニュー>プロジェクト>プロパティ (プロジェクト・エクスプローラから該当プロジェクトを右クリック、プロパティでも可)を選択して、プロパティ画面を開きます。プロパティ画面では、右ペインからJavaのビルド・パスを選択、ライブラリタブから外部Jarを追加してください。

ViewPagerを使う

ViewPagerはページ送りを簡単に実現できるコンポーネント(クラス)です。Viewという名前がついていますが、レイアウトファイル(xmlでの定義からの生成)やViewコンテナ(LinerLayout)なども利用できます。
ViewPagerを使う際の作法として、Viewの切り替え操作用にPagerAdapterを実装する必要があります。

まずはじめに、レイアウトファイルにViewPagerを配置して、ソースコードから参照可能な状態にしておきましょう。
■layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<android.support.v4.view.ViewPager
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/viewpager"/>
</LinearLayout>

レイアウトファイルmain.xmlの7行目でViewPager要素を記述、R.id.viewpagerを割り当てます。

ViewPagerの設定

ソースコードは以下の通りです。
■src/ViewPagerActivity.java

	private Context mContext;
	private MyPagerAdapter mPagerAdapter;
	private ViewPager mViewPager;
        …省略…
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mContext = this;
        mPagerAdapter = new MyPagerAdapter();
        mViewPager = (ViewPager) findViewById(R.id.viewpager);
        mViewPager.setAdapter(mPagerAdapter);
    }

onCreateメソッド内11行目、PagerAdapterを継承してMyPagerAdapterを作成します。
13行目、作成したアダプタをViewPagerに設定して準備完了です。

ViewPagerは指を動かした際、アニメーションする際など、イベントごとにPagerAdapterを呼び出します。
PagerAdapterにはそれらイベントをトリガに、、画面に表示したいViewやViewコンテナ、レイアウトファイルを生成/破棄する役割があります。

PagerAdapterの作成

外部ライブラリということで、javadocが標準状態では効かないなど、リファレンスを見る機会が少ないため、
サンプルコードのコメントは多めにしてあります。詳しい挙動についてはコメントを参照しながら確認してください。

メソッド名説明
getCountメソッド表示するView(またはコンテナ)の総数
instantiateItemメソッドページの生成を行う
destroyItemメソッドページの破棄を行う。instantiateItemメソッドとペア。
isViewFromObjectメソッドページを構成するViewの判定

■src/ViewPagerActivity.java

	private static int NUM_OF_VIEWS = 5;
	private static int[] mViewColor = {Color.RED, Color.BLACK, Color.BLUE, Color.GREEN, Color.DKGRAY};

    private class MyPagerAdapter extends PagerAdapter{

		@Override
		public int getCount() {
			//Pagerに登録したビューの数を返却。サンプルは固定なのでNUM_OF_VIEWS
			return NUM_OF_VIEWS;
		}

	    /**
	     * ページを生成する
	     * position番目のViewを生成し返却するために利用
	     * @param container: 表示するViewのコンテナ
	     * @param position : インスタンス生成位置
	     * @return ページを格納しているコンテナを返却すること。サンプルのようにViewである必要は無い。
	     */
		@Override
		public Object instantiateItem(View collection, int position) {
			TextView tv = new TextView(mContext);
			tv.setText("Hello, world! myPostion :" + position);
			tv.setTextColor(Color.WHITE);
			tv.setTextSize(30);
			tv.setBackgroundColor(mViewColor[position]);

			((ViewPager) collection).addView(tv,0);

			return tv;
		}
          ...省略...
        }
}

まず、Viewを表示するinstantiateItemメソッドの実装です。このメソッドでページ送りの際に表示する画面を作成します。
サンプルでは、27行目のように現在位置(ページの位置情報)を元に、Viewの背景色を変えています。

PagerAdapterクラスdestroyItemメソッドの実装

生成の次は破棄するdestroyItemメソッドです。
■src/ViewPagerActivity.java

    private class MyPagerAdapter extends PagerAdapter{
          ...省略...
		/**
	     * ページを破棄する。
	     * postion番目のViweを削除するために利用
	     * @param container: 削除するViewのコンテナ
	     * @param position : インスタンス削除位置
	     * @param object   : instantiateItemメソッドで返却したオブジェクト
	     */
		@Override
		public void destroyItem(View collection, int position, Object view) {
			//ViewPagerに登録していたTextViewを削除する
			((ViewPager) collection).removeView((TextView) view);
		}
          ...省略...

destroyItemメソッドは第2引数にinstantiateItemメソッドで生成したViewのオブジェクトが引き渡される特徴があります。
サンプルコードのdestroyItemメソッドでは単純にTextViewを生成しているため削除は(ViewPagerクラスの親クラスの)ViewGroupクラスのremoveViewメソッドを実行しています。
表示しているモノが簡単なView以外の場合もうすこし複雑になるはずです。
また破棄する情報などがあればdestroyItemメソッドで一緒に行えばいいでしょう。

PagerAdapterクラスisViewFromObjectメソッドの実装

ここまででほとんど実装は完了していますが、
最後にフォーカスや表示の調整のためにViewPagerから頻繁に呼び出されるisViewFromObjectについても紹介しておきます。
■src/ViewPagerActivity.java

    private class MyPagerAdapter extends PagerAdapter{
          ...省略...
		@Override
		public boolean isViewFromObject(View view, Object object) {
			//表示するViewがコンテナに含まれているか判定する(表示処理のため)
			//objecthainstantiateItemメソッドで返却したオブジェクト。
			//今回はTextViewなので以下の通りオブジェクト比較
			return view==((TextView)object);
		}
          ...省略...

isViewFromObjectメソッドでは第2引数のobjectに第1引数のviewが含まれているか、判定する必要があります。
8行目のように簡単な判定文になることは稀で、実際はコンテナに入っているViewを取り出して個別に比較する処理がいります。
(スワイプ中のページ送りのフォーカスや表示調整に使ってると推測しています。きっちりやった方がいいでしょう)

以上、お疲れ様でした!

2 Comments