次の方法で共有


Xamarin.Android を使った ListView の外観のカスタマイズ

ListView の外観は、表示される行のレイアウトによって決まります。 ListView の外観を変更するには、異なる行レイアウトを使います。

組み込みの行ビュー

Android.Resource.Layout を使って参照できる組み込みビューが 12 個あります。

  • TestListItem - 最小限の書式設定を備えた 1 行のテキスト。

  • SimpleListItem1 - 1 行のテキスト。

  • SimpleListItem2 - 2 行のテキスト。

  • SimpleSelectableListItem - 単一または複数の項目選択をサポートする 1 行のテキスト (API レベル 11 で追加)。

  • SimpleListItemActivated1 - SimpleListItem1 と似ていますが、背景色は行が選択されたことを示します (API レベル 11 で追加)。

  • SimpleListItemActivated2 - SimpleListItem2 と似ていますが、背景色は行が選択されたことを示します (API レベル 11 で追加)。

  • SimpleListItemChecked - 選択を示すチェック マークを表示します。

  • SimpleListItemMultipleChoice - 複数選択の選択項目を示すチェック ボックスを表示します。

  • SimpleListItemSingleChoice - 相互に排他的な選択項目を示すラジオ ボタンを表示します。

  • TwoLineListItem - 2 行のテキスト。

  • ActivityListItem - 画像を含む 1 行のテキスト。

  • SimpleExpandableListItem - カテゴリごとに行をグループ化し、各グループを展開または折りたたむことができます。

組み込みの各行ビューには、それに関連付けられた組み込みスタイルがあります。 以下のスクリーンショットは、各ビューがどのように表示されるかを示しています。

TestListItem、SimpleSelectableListItem、SimpleListitem1、SimpleListItem2 のスクリーンショット

SimpleListItemActivated1、SimpleListItemActivated2、SimpleListItemChecked、SimpleListItemMultipleChecked のスクリーンショット

SimpleListItemSingleChoice、TwoLineListItem、ActivityListItem、SimpleExpandableListItem のスクリーンショット

BuiltInViews/HomeScreenAdapter.cs サンプル ファイル (BuiltInViews ソリューション内) には、展開できないリスト項目画面を生成するコードが含まれています。 ビューは、次のように GetView メソッドで設定されます。

view = context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleListItem1, null);

その後、Android.Resource.Id に含まれる標準コントロール識別子 Text1Text2Icon を参照してビューのプロパティを設定できます (ビューに含まれていないプロパティは設定しないでください。例外がスローされます)。

view.FindViewById<TextView>(Android.Resource.Id.Text1).Text = item.Heading;
view.FindViewById<TextView>(Android.Resource.Id.Text2).Text = item.SubHeading;
view.FindViewById<ImageView>(Android.Resource.Id.Icon).SetImageResource(item.ImageResourceId); // only use with ActivityListItem

BuiltInExpandableViews/ExpandableScreenAdapter.cs サンプル ファイル (BuiltInViews ソリューション内) には、SimpleExpandableListItem 画面を生成するコードが含まれています。 グループ ビューは、次のように GetGroupView メソッドで設定されます。

view = context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleExpandableListItem1, null);

子ビューは、次のように GetChildView メソッドで設定されます。

view = context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleExpandableListItem2, null);

グループ ビューと子ビューのプロパティは、上に示したように標準の Text1 および Text2 コントロール識別子を参照して設定できます。 SimpleExpandableListItem のスクリーンショット (上に表示) は、1 行のグループ ビュー (SimpleExpandableListItem1) と 2 行の子ビュー (SimpleExpandableListItem2) の例を示しています。 または、グループ ビューを 2 行 (SimpleExpandableListItem2) に構成し、子ビューを 1 行 (SimpleExpandableListItem1) に構成することも、グループ ビューと子ビューの両方に同じ行数を含めることもできます。

アクセサリ

行には、選択状態を示すためにビューの右側にアクセサリを追加できます。

  • SimpleListItemChecked - チェック マークをインジケーターとして使って単一選択のリストを作成します。

  • SimpleListItemSingleChoice - 選択が 1 つだけ可能なラジオ ボタン型のリストを作成します。

  • SimpleListItemMultipleChoice - 複数選択が可能なチェックボックス型のリストを作成します。

上記のアクセサリは、次の画面にそれぞれの順序で示されています。

SimpleListItemChecked、SimpleListItemSingleChoice、SimpleListItemMultipleChoice とアクセサリのスクリーンショット

これらのアクセサリのいずれかを表示するには、必要なレイアウト リソース ID をアダプターに渡し、それから必要な行の選択状態を手動で設定します。 このコード行は、次のレイアウトのいずれかを使って Adapter を作成して割り当てる方法を示しています。

ListAdapter = new ArrayAdapter<String>(this, Android.Resource.Layout.SimpleListItemChecked, items);

ListView 自体は、表示されているアクセサリに関係なく、さまざまな選択モードをサポートしています。 混乱を避けるため、SingleChoice アクセサリでは Single 選択モードを使い、MultipleChoice スタイルでは Checked または Multiple モードを使います。 選択モードは、ListViewChoiceMode プロパティによって制御されます。

API レベルの処理

Xamarin.Android の以前のバージョンでは、列挙型が整数プロパティとして実装されていました。 最新バージョンでは、適切な .NET 列挙型が導入されており、潜在的なオプションを簡単に検出できるようになりました。

対象とする API レベルに応じて、ChoiceMode は整数または列挙のいずれかになります。 サンプル ファイル AccessoryViews/HomeScreen.cs には、Gingerbread API をターゲットにする場合にコメント アウトされたブロックがあります。

// For targeting Gingerbread the ChoiceMode is an int, otherwise it is an
// enumeration.

lv.ChoiceMode = Android.Widget.ChoiceMode.Single; // 1
//lv.ChoiceMode = Android.Widget.ChoiceMode.Multiple; // 2
//lv.ChoiceMode = Android.Widget.ChoiceMode.None; // 0

// Use this block if targeting Gingerbread or lower
/*
lv.ChoiceMode = 1; // Single
//lv.ChoiceMode = 0; // none
//lv.ChoiceMode = 2; // Multiple
//lv.ChoiceMode = 3; // MultipleModal
*/

プログラムによる項目の選択

どの項目を "選択" するかを手動で設定するには、SetItemChecked メソッドを使います (複数選ぶ場合は複数回呼び出すことができます)。

// Set the initially checked row ("Fruits")
lv.SetItemChecked(1, true);

コードでは、複数選択とは異なる方法で単一選択を検出する必要もあります。 Single モードでどの行が選ばれているかを確認するには、整数プロパティ CheckedItemPosition を使います。

FindViewById<ListView>(Android.Resource.Id.List).CheckedItemPosition

Multiple モードで選択されている行を確認するには、CheckedItemPositions SparseBooleanArrayをループする必要があります。 スパース配列は、値が変更されたエントリのみを含むディクショナリのようなものであるため、次のコード スニペットに示すように、リスト内で何が選ばれているかを知るには、配列全体を走査して true 値を探す必要があります。

var sparseArray = FindViewById<ListView>(Android.Resource.Id.List).CheckedItemPositions;
for (var i = 0; i < sparseArray.Size(); i++ )
{
   Console.Write(sparseArray.KeyAt(i) + "=" + sparseArray.ValueAt(i) + ",");
}
Console.WriteLine();

カスタム行レイアウトの作成

4 つの組み込みの行ビューは非常に単純です。 より複雑なレイアウト (メール、ツイート、連絡先情報の一覧など) を表示するには、カスタム ビューが必要です。 カスタム ビューは、通常、Resources/Layout ディレクトリで AXML ファイルとして宣言され、カスタム アダプターによってリソース ID を使って読み込まれます。 ビューには、カスタムの色、フォント、レイアウトを備えた任意の数の表示クラス (TextView、ImageView、その他のコントロールなど) を含めることができます。

この例は、さまざまな点で前の例とは異なります。

  • ListActivity ではなく、Activity から継承します。 任意の ListView の行をカスタマイズできますが、他のコントロール (見出し、ボタン、その他のユーザー インターフェイス要素など) を Activity レイアウトに含めることもできます。 この例では、説明のために ListView の上に見出しを追加します。

  • 画面には AXML レイアウト ファイルが必要です。前の例では、ListActivity にはレイアウト ファイルは必要ありません。 この AXML には、ListView コントロール宣言が含まれています。

  • 各行をレンダリングするには AXML レイアウト ファイルが必要です。 この AXML ファイルには、カスタム フォントと色の設定を備えたテキストとイメージのコントロールが含まれています。

  • 省略可能なカスタム セレクター XML ファイルを使って、行が選ばれたときの外観を設定します。

  • Adapter 実装では、GetView オーバーライドからカスタム レイアウトが返されます。

  • ItemClick は別の方法で宣言する必要があります (イベント ハンドラーは、ListActivityOnListItemClick をオーバーライドするのではなく、ListView.ItemClick にアタッチされます)。

これらの変更については、以下で詳しく説明します。まず、アクティビティのビューとカスタム行ビューの作成から始めて、それらをレンダリングするためのアダプターとアクティビティへの変更について説明します。

ListView のアクティビティ レイアウトへの追加

HomeScreenListActivity から継承されなくなり、既定のビューがないため、HomeScreen のビュー用にレイアウト AXML ファイルを作成する必要があります。 この例では、ビューにはデータを表示するための見出し (TextView を使用) と ListView が含まれます。 レイアウトは、次に示す Resources/Layout/HomeScreen.axml ファイルで定義されます。

<?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">
    <TextView android:id="@+id/Heading"
        android:text="Vegetable Groups"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#00000000"
        android:textSize="30dp"
        android:textColor="#FF267F00"
        android:textStyle="bold"
        android:padding="5dp"
    />
    <ListView android:id="@+id/List"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:cacheColorHint="#FFDAFF7F"
    />
</LinearLayout>

(ListActivity ではなく) カスタム レイアウトで Activity を使う利点は、この例の見出し TextView など、付加的なコントロールを画面に追加できることです。

カスタム行レイアウトの作成

リスト ビューに表示される各行のカスタム レイアウトを含めるには、別の AXML レイアウト ファイルが必要です。 この例では、行の背景が緑色、テキストが茶色、画像が右揃えになります。 このレイアウトを宣言する Android XML マークアップは、Resources/Layout/CustomView.axml で説明されています。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout  xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:background="#FFDAFF7F"
   android:padding="8dp">
    <LinearLayout android:id="@+id/Text"
       android:orientation="vertical"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:paddingLeft="10dip">
        <TextView
         android:id="@+id/Text1"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:textColor="#FF7F3300"
         android:textSize="20dip"
         android:textStyle="italic"
         />
        <TextView
         android:id="@+id/Text2"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:textSize="14dip"
         android:textColor="#FF267F00"
         android:paddingLeft="100dip"
         />
    </LinearLayout>
    <ImageView
        android:id="@+id/Image"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:padding="5dp"
        android:src="@drawable/icon"
        android:layout_alignParentRight="true" />
</RelativeLayout >

カスタム行レイアウトにはさまざまなコントロールを含めることができますが、スクロールのパフォーマンスは、複雑なデザインや画像の使用 (特にネットワーク経由で読み込む必要がある場合) によって影響を受ける可能性があります。 スクロールのパフォーマンスの問題への対処方法の詳細については、Google の記事を参照してください。

カスタム行ビューの参照

カスタム アダプター実装の例は HomeScreenAdapter.cs にあります。 主要なメソッドは GetView で、リソース ID Resource.Layout.CustomView を使ってカスタム AXML を読み込んでから、ビュー内の各コントロールのプロパティを、それを返す前に設定します。 完全なアダプター クラスを次に示します。

public class HomeScreenAdapter : BaseAdapter<TableItem> {
   List<TableItem> items;
   Activity context;
   public HomeScreenAdapter(Activity context, List<TableItem> items)
       : base()
   {
       this.context = context;
       this.items = items;
   }
   public override long GetItemId(int position)
   {
       return position;
   }
   public override TableItem this[int position]
   {
       get { return items[position]; }
   }
   public override int Count
   {
       get { return items.Count; }
   }
   public override View GetView(int position, View convertView, ViewGroup parent)
   {
       var item = items[position];
       View view = convertView;
       if (view == null) // no view to re-use, create new
           view = context.LayoutInflater.Inflate(Resource.Layout.CustomView, null);
       view.FindViewById<TextView>(Resource.Id.Text1).Text = item.Heading;
       view.FindViewById<TextView>(Resource.Id.Text2).Text = item.SubHeading;
       view.FindViewById<ImageView>(Resource.Id.Image).SetImageResource(item.ImageResourceId);
       return view;
   }
}

アクティビティでのカスタム ListView の参照

HomeScreen クラスは Activity を継承するようになったため、クラス内で ListView フィールドが宣言され、AXML で宣言されたコントロールへの参照が保持されます。

ListView listView;

次に、クラスは、SetContentView メソッドを使ってアクティビティのカスタム レイアウト AXML を読み込む必要があります。 その後、レイアウト内で ListView コントロールを見つけて、アダプターを作成して割り当て、クリック ハンドラーを割り当てます。 OnCreate メソッドのコードを次に示します。

SetContentView(Resource.Layout.HomeScreen); // loads the HomeScreen.axml as this activity's view
listView = FindViewById<ListView>(Resource.Id.List); // get reference to the ListView in the layout

// populate the listview with data
listView.Adapter = new HomeScreenAdapter(this, tableItems);
listView.ItemClick += OnListItemClick;  // to be defined

最後に、ItemClick ハンドラーを定義する必要があります。この場合は、Toast メッセージを表示するだけです。

void OnListItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
   var listView = sender as ListView;
   var t = tableItems[e.Position];
   Android.Widget.Toast.MakeText(this, t.Heading, Android.Widget.ToastLength.Short).Show();
}

結果の画面は次のようになります。

結果の CustomRowView のスクリーンショット

行セレクターの色のカスタマイズ

行がタッチされると、ユーザー フィードバックのためにそれが強調表示されます。 CustomView.axml のようにカスタム ビューが背景色として指定されている場合、選択の強調表示もオーバーライドされます。 CustomView.axml のこのコード行は背景を明るい緑色に設定しますが、これは行がタッチされたときに視覚的なインジケーターがないことも意味します。

android:background="#FFDAFF7F"

強調表示動作を再度有効にし、使われる色をカスタマイズするには、代わりに背景属性をカスタム セレクターに設定します。 セレクターでは、既定の背景色と強調表示の色の両方を宣言します。 ファイル Resources/Drawable/CustomSelector.xml には次の宣言が含まれています。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false"
  android:state_selected="false"
  android:drawable="@color/cellback" />
<item android:state_pressed="true" >
  <shape>
     <gradient
      android:startColor="#E77A26"
        android:endColor="#E77A26"
        android:angle="270" />
  </shape>
</item>
<item android:state_selected="true"
  android:state_pressed="false"
  android:drawable="@color/cellback" />
</selector>

カスタム セレクターを参照するには、CustomView.axml の背景属性を次のように変更します。

android:background="@drawable/CustomSelector"

選択した行行と対応する Toast メッセージは次のようになります。

選択した行の名前を表示するトースト メッセージが表示された、オレンジ色の選択された行

カスタム レイアウトでのちらつきの防止

Android では、レイアウト情報をキャッシュすることで、ListView スクロールのパフォーマンスを向上させようとしています。 スクロールするデータのリストが長い場合は、アクティビティの AXML 定義の ListView 宣言で android:cacheColorHint プロパティを (カスタム行レイアウトの背景と同じ色の値に) 設定する必要もあります。 このヒントを含めないと、ユーザーがカスタム行の背景色を持つリストをスクロールするときに "ちらつき" が発生する可能性があります。