ViewPager とフラグメント

ViewPager は、ゲスト ナビゲーションを実装できるレイアウト マネージャーです。 Gestural ナビゲーションを使用すると、ユーザーは左右にスワイプしてデータのページをステップスルーできます。 このガイドでは、データ ページとしてフラグメントを使用して、ViewPager でスワイプ可能な UI を実装する方法について説明します。

概要

ViewPager は、多くの場合、 内の各ページのライフサイクルを管理しやすくするために、フラグメントと組み合わせて使用されます ViewPager。 このチュートリアルでは、 ViewPager を使用して FlashCardPager というアプリを作成し、フラッシュ カードに一連の数学の問題を示します。 各フラッシュ カードはフラグメントとして実装されます。 ユーザーはフラッシュ カードを左右にスワイプし、数学の問題をタップしてその答えを明らかにします。 このアプリは、Fragmentフラッシュ カードごとに インスタンスを作成し、 からFragmentPagerAdapter派生したアダプターを実装します。 Viewpager と Views では、ほとんどの作業はライフサイクル メソッドでMainActivity行われました。 FlashCardPager では、ほとんどの作業は、そのライフサイクル メソッドの 1 つで によってFragment行われます。

このガイドでは、フラグメントの基本については説明しません。Xamarin.Android でフラグメントにまだ慣れていない場合は、「 フラグメント 」を参照してフラグメントの使用を開始してください。

アプリ プロジェクトを開始する

FlashCardPager という名前の新しい Android プロジェクトを作成します。 次に、NuGet パッケージ マネージャーを起動します (NuGet パッケージのインストールの詳細については、「 チュートリアル: プロジェクトに NuGet を含める」を参照してください)。 Viewpager と Views で説明されているように、Xamarin.Android.Support.v4 パッケージを見つけてインストールします。

サンプル データ ソースを追加する

FlashCardPager では、データ ソースは クラスによってFlashCardDeck表されるフラッシュ カードのデッキです。このデータ ソースは、 に項目コンテンツをViewPager提供します。 FlashCardDeck には、数学の問題と回答の既製のコレクションが含まれています。 コンストラクターには FlashCardDeck 引数は必要ありません。

FlashCardDeck flashCards = new FlashCardDeck();

のフラッシュ カードFlashCardDeckのコレクションは、各フラッシュ カードにインデクサーがアクセスできるように編成されています。 たとえば、次のコード行は、デッキの 4 番目のフラッシュ カード問題を取得します。

string problem = flashCardDeck[3].Problem;

このコード行は、前の問題に対応する回答を取得します。

string answer = flashCardDeck[3].Answer;

の実装の FlashCardDeck 詳細は 理解 ViewPagerに関連しないため、 FlashCardDeck コードはここに記載されていません。 の FlashCardDeck ソース コードは、 FlashCardDeck.cs で入手できます。 このソース ファイルをダウンロードし (または、コードをコピーして新しい FlashCardDeck.cs ファイルに貼り付けます)、プロジェクトに追加します。

ViewPager レイアウトを作成する

Resources/layout/Main.axml を開き、その内容を次の XML に置き換えます。

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

    </android.support.v4.view.ViewPager>

この XML は、 ViewPager 画面全体を占める を定義します。 はサポート ライブラリにパッケージ化されているためViewPager、完全修飾名 android.support.v4.view.ViewPager を使用する必要があることに注意してください。 ViewPager、Android サポート ライブラリ v4 からのみ使用できます。Android SDK では使用できません。

ViewPager を設定する

MainActivity.cs を編集し、次usingのステートメントを追加します。

using Android.Support.V4.View;
using Android.Support.V4.App;

MainActivityから派生するようにクラス宣言をFragmentActivity変更します。

public class MainActivity : FragmentActivity

MainActivityは、フラグメントのサポートを管理する方法を知っているためFragmentActivity、 ではなく からFragmentActivityActivity派生します。 OnCreate メソッドを次のコードに置き換えます。

protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);
    SetContentView(Resource.Layout.Main);
    ViewPager viewPager = FindViewById<ViewPager>(Resource.Id.viewpager);
    FlashCardDeck flashCards = new FlashCardDeck();
}

このコードは、次の処理を実行します。

  1. Main.axml レイアウト リソースからビューを設定します。

  2. レイアウトから への ViewPager 参照を取得します。

  3. 新しい を FlashCardDeck データ ソースとしてインスタンス化します。

このコードをビルドして実行すると、次のスクリーンショットのような表示が表示されます。

空の ViewPager を含む FlashCardPager アプリのスクリーンショット

この時点で、 は 空です。これは、 ViewPager に入力 ViewPagerするフラグメントが不足しており、 FlashCardDeck のデータからこれらのフラグメントを作成するためのアダプターがないためです。

以降のセクションでは、 FlashCardFragment は各フラッシュ カードの機能を実装するために 作成されFragmentPagerAdapter、 内のデータから作成されたフラグメントに を接続ViewPagerするために がFlashCardDeck作成されます。

フラグメントを作成する

各フラッシュ カードは、 と呼ばれる FlashCardFragmentUI フラグメントによって管理されます。 FlashCardFragmentのビューには、1 つのフラッシュ カードに含まれる情報が表示されます。 の FlashCardFragment 各インスタンスは、 によって ViewPagerホストされます。 FlashCardFragmentのビューは、フラッシュカード問題のテキストを表示する で構成TextViewされます。 このビューでは、 を使用Toastして、ユーザーがフラッシュ カード質問をタップしたときに回答を表示するイベント ハンドラーが実装されます。

FlashCardFragment レイアウトを作成する

実装する前 FlashCardFragment に、そのレイアウトを定義する必要があります。 このレイアウトは、1 つのフラグメントのフラグメント コンテナー レイアウトです。 flashcard_layout.axml という名前の新しい Android レイアウトを Resources/layout に追加します。 Resources/layout/flashcard_layout.axml を開き、その内容を次のコードに置き換えます。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/flash_card_question"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:textAppearance="@android:style/TextAppearance.Large"
            android:textSize="100sp"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:text="Question goes here" />
    </RelativeLayout>

このレイアウトでは、単一のフラッシュ カード フラグメントが定義されます。各フラグメントは、大きな (100sp) フォントを使用して数学のTextView問題を表示する で構成されます。 このテキストは、フラッシュ カードの垂直方向と水平方向の中央に配置されます。

初期 FlashCardFragment クラスを作成する

FlashCardFragment.cs という名前の新しいファイルを追加し、その内容を次のコードに置き換えます。

using System;
using Android.OS;
using Android.Views;
using Android.Widget;
using Android.Support.V4.App;

namespace FlashCardPager
{
    public class FlashCardFragment : Android.Support.V4.App.Fragment
    {
        public FlashCardFragment() { }

        public static FlashCardFragment newInstance(String question, String answer)
        {
            FlashCardFragment fragment = new FlashCardFragment();
            return fragment;
        }
        public override View OnCreateView (
            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            View view = inflater.Inflate (Resource.Layout.flashcard_layout, container, false);
            TextView questionBox = (TextView)view.FindViewById (Resource.Id.flash_card_question);
            return view;
        }
    }
}

このコードは、フラッシュ カードの表示に使用される基本的なFragment定義をスタブします。 FlashCardFragmentは、 でAndroid.Support.V4.App.Fragment定義されている のサポート ライブラリ バージョンFragmentから派生しています。 コンストラクターが空であるため、ファクトリ メソッドを newInstance 使用してコンストラクターの代わりに新しい FlashCardFragment を作成します。

ライフサイクル メソッドは OnCreateView 、 を作成して構成します TextView。 フラグメント TextView のレイアウトを拡張し、拡張された TextView を呼び出し元に返します。 LayoutInflaterViewGroup は に渡され OnCreateView 、レイアウトを膨らませることができます。 バンドル savedInstanceState には、保存された OnCreateView 状態から を TextView 再作成するために を使用するデータが含まれています。

フラグメントのビューは、 の呼び出しによって明示的に inflater.Inflate拡張されます。 引数はcontainerビューの親でありfalse、フラグは、拡大されたビューをビューの親に追加しないようにインフレータに指示します (このチュートリアルで後述するアダプターのGetItemメソッドを呼び出すとViewPager追加されます)。

FlashCardFragment に状態コードを追加する

アクティビティと同様に、フラグメントには、状態の Bundle 保存と取得に使用する が含まれます。 FlashCardPager では、関連付Bundleけられているフラッシュ カードの質問と回答のテキストを保存するために使用されます。 FlashCardFragment.cs で、クラス定義の先頭に次BundleのキーをFlashCardFragment追加します。

private static string FLASH_CARD_QUESTION = "card_question";
private static string FLASH_CARD_ANSWER = "card_answer";

ファクトリ メソッドを newInstance 変更して、オブジェクトを Bundle 作成し、上記のキーを使用して、インスタンス化後に渡された質問と回答のテキストをフラグメントに格納します。

public static FlashCardFragment newInstance(String question, String answer)
{
    FlashCardFragment fragment = new FlashCardFragment();

    Bundle args = new Bundle();
    args.PutString(FLASH_CARD_QUESTION, question);
    args.PutString(FLASH_CARD_ANSWER, answer);
    fragment.Arguments = args;

    return fragment;
}

フラグメント ライフサイクル メソッド OnCreateView を変更して、渡された Bundle からこの情報を取得し、質問テキストを TextBoxに読み込みます。

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    string question = Arguments.GetString(FLASH_CARD_QUESTION, "");
    string answer = Arguments.GetString(FLASH_CARD_ANSWER, "");

    View view = inflater.Inflate(Resource.Layout.flashcard_layout, container, false);
    TextView questionBox = (TextView)view.FindViewById(Resource.Id.flash_card_question);
    questionBox.Text = question;

    return view;
}

この変数は answer ここでは使用されませんが、後でイベント ハンドラー コードがこのファイルに追加されるときに使用されます。

アダプターを作成する

ViewPager は、 と データ ソースの間 ViewPager に存在するアダプター コントローラー オブジェクトを使用します (ViewPager アダプター に関する記事の図を参照)。 このデータにアクセスするには、 ViewPager から PagerAdapter派生したカスタム アダプターを指定する必要があります。 この例ではフラグメントを使用するため、 から派生した – FragmentPagerAdapter が使用FragmentPagerAdapterされますPagerAdapterFragmentPagerAdapter は、ユーザーがページ Fragment に戻ることができる限り、フラグメント マネージャーに永続的に保持される として各ページを表します。 ユーザーが のページ ViewPagerをスワイプすると、 は FragmentPagerAdapter データ ソースから情報を抽出し、それを使用して を作成 Fragmentして、 ViewPager を表示します。

を実装する場合は FragmentPagerAdapter、次をオーバーライドする必要があります。

  • Count – 使用可能なビュー (ページ) の数を返す読み取り専用プロパティです。

  • GetItem – 指定したページに表示するフラグメントを返します。

FlashCardDeckAdapter.cs という名前の新しいファイルを追加し、その内容を次のコードに置き換えます。

using System;
using Android.Views;
using Android.Widget;
using Android.Support.V4.App;

namespace FlashCardPager
{
    class FlashCardDeckAdapter : FragmentPagerAdapter
    {
        public FlashCardDeckAdapter (Android.Support.V4.App.FragmentManager fm, FlashCardDeck flashCards)
            : base(fm)
        {
        }

        public override int Count
        {
            get { throw new NotImplementedException(); }
        }

        public override Android.Support.V4.App.Fragment GetItem(int position)
        {
            throw new NotImplementedException();
        }
    }
}

このコードは、重要な FragmentPagerAdapter 実装をスタブします。 以降のセクションでは、これらの各メソッドを動作するコードに置き換えます。 コンストラクターの目的は、フラグメント マネージャーを の基底クラス コンストラクターに FlashCardDeckAdapter渡すことです。

アダプター コンストラクターを実装する

アプリが を FlashCardDeckAdapterインスタンス化すると、フラグメント マネージャーとインスタンス化された への参照が提供されます FlashCardDeckFlashCardDeckAdapter.cs のクラスの先頭に次のFlashCardDeckAdapterメンバー変数を追加します。

public FlashCardDeck flashCardDeck;

コンストラクターに次のコード行を FlashCardDeckAdapter 追加します。

this.flashCardDeck = flashCards;

このコード行には、 が使用する FlashCardDeck インスタンスが FlashCardDeckAdapter 格納されます。

Count を実装する

実装はCount比較的簡単です。フラッシュ カード デッキ内のフラッシュ カードの数を返します。 Count を次のコードに置き換えます。

public override int Count
{
    get { return flashCardDeck.NumCards; }
}

FlashCardDeck プロパティはNumCards、データ セット内のフラッシュ カードの数 (フラグメントの数) を返します。

GetItem を実装する

メソッドは GetItem 、指定された位置に関連付けられているフラグメントを返します。 がフラッシュカードデッキ内の位置に対して呼び出されるとGetItem、その位置でフラッシュカード問題を表示するように構成された を返しますFlashCardFragmentGetItem メソッドを次のコードに置き換えます。

public override Android.Support.V4.App.Fragment GetItem(int position)
{
    return (Android.Support.V4.App.Fragment)
        FlashCardFragment.newInstance (
            flashCardDeck[position].Problem, flashCardDeck[position].Answer);
}

このコードは、次の処理を実行します。

  1. 指定した位置について、デッキ内の FlashCardDeck 数学の問題文字列を検索します。

  2. デッキで指定した位置の FlashCardDeck 応答文字列を検索します。

  3. ファクトリ メソッド newInstanceFlashCardFragment呼び出し、フラッシュ カード問題を渡し、文字列に応答します。

  4. その位置の質問と回答のテキストを含む新しいフラッシュ カードFragmentを作成して返します。

ViewPager をレンダリングすると、フラッシュ カード デッキに存在する数学の問題文字列をposition含む が表示されますTextBoxFragmentposition

アダプターを ViewPager に追加する

FlashCardDeckAdapter 実装されたので、 に追加 ViewPagerします。 MainActivity.cs で、 メソッドの末尾に次のコード行をOnCreate追加します。

FlashCardDeckAdapter adapter =
    new FlashCardDeckAdapter(SupportFragmentManager, flashCards);
viewPager.Adapter = adapter;

このコードは、 をインスタンス化し FlashCardDeckAdapter、最初の引数で を SupportFragmentManager 渡します。 (FragmentActivity の プロパティはSupportFragmentManager、 へのFragmentManager参照を取得するために使用されます。の詳細については、「フラグメントFragmentManager管理」を参照してください)。

これでコア実装が完了しました。アプリをビルドして実行します。 次のスクリーンショットの左側に示すように、フラッシュ カード デッキの最初の画像が画面に表示されます。 左にスワイプして他のフラッシュ カードを表示し、右にスワイプしてフラッシュ カード デッキ内に戻ります。

ポケットベル インジケーターのない FlashCardPager アプリのスクリーンショットの例

ポケットベル インジケーターを追加する

この最小限ViewPagerの実装では、各フラッシュ カードがデッキに表示されますが、ユーザーがデッキ内のどこにいるかは示されません。 次の手順では、 を追加します PagerTabStrip。 は PagerTabStrip 、表示される問題番号をユーザーに通知し、前のフラッシュ カードと次のフラッシュ カードのヒントを表示してナビゲーション コンテキストを提供します。

Resources/layout/Main.axml を開き、レイアウトに を追加PagerTabStripします。

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

  <android.support.v4.view.PagerTabStrip
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_gravity="top"
      android:paddingBottom="10dp"
      android:paddingTop="10dp"
      android:textColor="#fff" />

</android.support.v4.view.ViewPager>

アプリをビルドして実行すると、各フラッシュ カードの上部に空PagerTabStripの が表示されます。

テキストなしの PagerTabStrip のクローズアップ

タイトルを表示する

各ページ タブにタイトルを追加するには、アダプターで メソッドを GetPageTitleFormatted 実装します。 ViewPager は (実装されている場合) を呼び出 GetPageTitleFormatted して、指定した位置にあるページを記述するタイトル文字列を取得します。 FlashCardDeckAdapter.cs の クラスに次のメソッドFlashCardDeckAdapterを追加します。

public override Java.Lang.ICharSequence GetPageTitleFormatted(int position)
{
    return new Java.Lang.String("Problem " + (position + 1));
}

このコードは、フラッシュ カード デッキ内の位置を問題番号に変換します。 結果の文字列は、 に返される Java StringViewPager変換されます。 この新しいメソッドを使用してアプリを実行すると、各ページに問題番号が PagerTabStripに表示されます。

各ページの上に問題番号が表示されている FlashCardPager のスクリーンショット

前後にスワイプして、各フラッシュ カードの上部に表示されているフラッシュ カード デッキの問題番号を確認できます。

ユーザー入力の処理

FlashCardPager では、 で ViewPager一連のフラグメント ベースのフラッシュ カードが表示されますが、各問題の答えを明らかにする方法はまだありません。 このセクションでは、 にイベント ハンドラーがFlashCardFragment追加され、ユーザーがフラッシュ カード問題のテキストをタップしたときに回答が表示されます。

FlashCardFragment.cs を開き、ビューが呼び出し元に返される直前に、メソッドのOnCreateView末尾に次のコードを追加します。

questionBox.Click += delegate
{
    Toast.MakeText(Activity.ApplicationContext,
            "Answer: " + answer, ToastLength.Short).Show();
};

このイベント ハンドラーは Click 、ユーザーが をタップしたときに表示されるトーストに応答を TextBox表示します。 answerに渡された Bundle から状態情報が読み取られたとき、変数は以前にOnCreateView初期化されました。 アプリをビルドして実行し、各フラッシュ カードの問題のテキストをタップして、次の答えを確認します。

数学の問題がタップされたときの FlashCardPager アプリトーストのスクリーンショット

このチュートリアルで示す FlashCardPager では、 からFragmentActivity派生した をMainActivity使用しますが、 からAppCompatActivity派生MainActivityすることもできます (フラグメントの管理のサポートも提供します)。 例を AppCompatActivity 表示するには、サンプル ギャラリーの FlashCardPager に関するページを参照してください。

まとめ

このチュートリアルでは、 を使用して基本 ViewPagerベースのアプリをビルドする方法の詳細な例を Fragment示しました。 フラッシュ カードの質問と回答、フラッシュ カードを表示するレイアウト、ViewPagerおよび FragmentPagerAdapter データ ソースに を接続ViewPagerするサブクラスを含むデータ ソースの例を示しました。 ユーザーがフラッシュ カード内を移動できるように、各ページの上部に問題番号を表示する を PagerTabStrip 追加する方法を説明する手順が含まれていました。 最後に、ユーザーがフラッシュ カード問題をタップしたときに応答を表示するイベント処理コードが追加されました。