Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
Xamarin逆引きTips

Xamarin逆引きTips

Xamarin.FormsでListViewコントロールを使用するには?

2015年3月4日

データの一覧を表示できる「リストビュー」はXamarin.Formsでも提供されている。その基本的な使用方法を解説。また、セルの高さ指定/プログラムによるスクロール/画像表示などの方法も説明する。

古谷 誠進(@furuya02
  • このエントリーをはてなブックマークに追加

 いろいろなアプリで比較的よく利用されるコントロールにリストビューがある。そして、Xamarin.FormsにもListViewビュー*1が提供されている。今回は、このListViewビューの使用方法について詳しく解説する*2

  • *1 「ListViewビュー」と呼ぶと、「ListViewコントロール」ではないのか? と違和感を覚えるかもしれないが、Xamarin.Formsでは、ButtonやLabelなどを含め、全て「ビュー」と呼んでいる(参考:Xamairn Developer Guide 「Xamarin.Forms Views」[英語])。
  • *2 なお本Tipsは、Windows上でVisual Studio 2013を使用してXamarin.Forms開発をすることを前提としている(編集部注: Mac上のXamarin Studioでも同様の手順で、本稿の内容が実現できることは確認している)。使用しているXamarin.Formsのバージョンは、プロジェクト作成時に利用されている「1.3.1.6296」である。

1. シナリオ

 最初に、簡単なテキストのみのListViewビューの使用方法を説明する。その後、そのスクロールや、セルの高さの変更、そして、画像と組み合わせた表示やグループ表示についても解説する。

2. Xamarin.Formsプロジェクトを作成する

 メニューバーの[ファイル]-[新規作成]-[プロジェクト]から表示したダイアログで、[テンプレート]-[Visual C#]-[Mobile Apps]-[Blank App (Xamarin.Forms Portable)]を選択し、名前を「ListViewSample」として[OK]ボタンを押す。

図1 「Blank App (Xamarin.Forms Portable)」の新規作成

3. テキストのみのリストビュー

 画面にテキストのみのListViewビューを表示するには、App.csファイルを以下のように修正する。

C#
using System;
using System.Collections.ObjectModel;
using System.Linq;
using Xamarin.Forms;
 
namespace ListViewSample{
  public class App : Application{
    public App(){
      MainPage = new MyPage();
    }
  
    ……省略……
 
  }
 
  internal class MyPage : ContentPage {
    public MyPage() {
      var ar = new ObservableCollection<String>();  // <-1
      foreach (var i in Enumerable.Range(0, 100)) { // <-2
        ar.Add(string.Format("item-{0}", i));
      }
      var listView = new ListView {
        ItemsSource = ar          // <-3
      };
 
      Content = new StackLayout { // <-4
        Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0), // iOSのみ上部にマージンをとる
        Children = {listView}
      };
    }
  }
 
}
ListViewビューを表示するコード(App.cs)

 最初に、表示するデータを保持するためにString型のObservableCollectionのインスタンスを生成し(1)、そこに100個のデータを追加した(2)。

 続いて、ListViewビューを生成し、そのItemsSourceプロパティに1で生成したデータをセットした(3)。

 Contentプロパティには、まずは、StackLayoutのインスタンスを設定し、そのChildrenとして、このListViewを配置した(4)。

 このコードを実行すると、次のような画面になる。

図2 テキストのみのListViewビューを表示(iOS) 図2 テキストのみのListViewビューを表示(Android)
図2 テキストのみのListViewビューを表示(iOS/Android)

4. セルの高さの指定

 セルの高さを変更するには、App.csファイルを以下のように修正する。

C#
namespace ListViewSample{
 
  ……省略……

  internal class MyPage : ContentPage {
    public MyPage() {
  
      ……省略……

      var listView = new ListView {
        ItemsSource = ar,
        RowHeight = 30 // <-1
      };

      ……省略……
    }
  }

}
ListViewビューを表示するコード(App.cs)

 ListViewクラスのRowHeightプロパティには、セルの高さを設定できる(1)。

 RowHeightプロパティに3070を指定した場合の画面は次のようになる。

図3 高さを指定した場合の表示( RowHeight=30 ) 図3 高さを指定した場合の表示( RowHeight=70 )
図3 高さを指定した場合の表示( RowHeight=30 / RowHeight=70 )

【コラム】個別の高さ指定

 セルの高さは個別に指定することもできるが、そのためには今回紹介できなかったカスタムセルを使用する必要がある。カスタムセルについては今後のTipsで詳しく解説する予定である。

図4 テキストの長さによってセルの高さを変えている例(iOS)
図4 テキストの長さによってセルの高さを変えている例(iOS)

5. スクロール

 ListViewビューのスクロールの動作を確認するために、App.csファイルを以下のように修正する。

C#
namespace ListViewSample{

  ……省略……

  internal class MyPage : ContentPage {
    public MyPage() {
      var ar = new ObservableCollection<String>();
      foreach (var i in Enumerable.Range(0, 100)) {
        ar.Add(string.Format("item-{0}", i));
      }
      var listView = new ListView {
        ItemsSource = ar
      };

      const int index = 20;                // <-1
      ar[index] += " target";              // <-2

      var buttonStart = new Button {       // <-3
        HorizontalOptions = LayoutOptions.FillAndExpand,
        Text = "Start",
        // ターゲットが先頭行に表示されるようにスクロールする
        Command = new Command(() => { listView.ScrollTo(ar[index], ScrollToPosition.Start, true); })
      };

      var buttonEnd = new Button {         // <-4
        HorizontalOptions = LayoutOptions.FillAndExpand,
        Text = "End",
        // ターゲットが最終行に表示されるようにスクロールする
        Command = new Command(() => { listView.ScrollTo(ar[index], ScrollToPosition.End, true); })
      };

      var buttonCenter = new Button {      // <-5
        HorizontalOptions = LayoutOptions.FillAndExpand,
        Text = "Center",
        // ターゲットが中間付近に表示されるようにスクロールする
        Command = new Command(() => { listView.ScrollTo(ar[index], ScrollToPosition.Center, true); })
      };

      var buttonMakeVisible = new Button { // <-6
        HorizontalOptions = LayoutOptions.FillAndExpand,
        Text = "MakeVisible",
        // ターゲットが表示されるまでスクロールする
        Command = new Command(() => { listView.ScrollTo(ar[index], ScrollToPosition.MakeVisible, true); })

      };

      Content = new StackLayout {
        Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0), // iOSのみ上部にマージンをとる
        Children = {
          new StackLayout {                // <-7
            Orientation = StackOrientation.Horizontal, 
            Children = {
              buttonStart,
              buttonEnd,
              buttonCenter,
              buttonMakeVisible
            }
          },
          listView
        }
      };
    }

}
スクロールの動作を確認するコード(App.cs)

 最初に、データリストの20番目のデータをスクロールの対象とし(1)、その対象を識別しやすいように表示文字列に「target」を追加した(2)。

 続いてボタンを4個生成した。それぞれのラベルを、[Start](3)、[End](4)、[Center](5)、[MakeVisible](6)とし、タッチ時にScrollToメソッドが実行されるようにした。

 ここで、ScrollToメソッドのパラメーターは、以下の通りである。

  • 第1パラメーター: スクロールの対象のオブジェクト
  • 第2パラメーター: スクロールポジション
  • 第3パラメーター: アニメーションの有無

 そして、スクロールポジションに指定できるのは、ScrollToPosition列挙体の以下の値である。

  • Start: ターゲットが表示領域の先頭行になるまでスクロールする
  • End: ターゲットが表示領域の最下行になるまでスクロールする
  • Center: ターゲットが表示領域の中央になるまでスクロールする
  • MakeVisible: ターゲットが表示領域に表示されるまでスクロールする

 最後に、生成した4個のボタンをStackLayoutを使用して横に並べて、ListViewビューの下に配置した(7)。

 このコードを実行して、ボタンをタップすると次のような画面になる。

図5 それぞれのボタンをタップした場合のスクロール動作([Start]) 図5 それぞれのボタンをタップした場合のスクロール動作([End]) 図5 それぞれのボタンをタップした場合のスクロール動作([Center])
図5 それぞれのボタンをタップした場合のスクロール動作([Start]/[End]/[Center])

 なお、ScrollToPosition.MakeVisibleは「ターゲットが表示されるまでスクロールする」という動作なので、もし、すでにターゲットが表示されている場合は、何も動作しない。そして、ターゲットが表示領域より上にある場合、最上行までスクロールし、表示領域より下にある場合は、最下行までスクロールすることになる。

【コラム】Windows Phoneでスクロールが動作しない(※1.3.5-pre1で解決済み)

 本記事では、AndroidおよびiOSの動作しか紹介していないが、Visual Studioを使用してXamarin.FormsのMobile Appsを作成すると、Windows Phone用のプロジェクトも同時に生成される。しかし、今回紹介したScrollToメソッドは、現在の最新stable(1.3.4.6332)でもWindows Phoneで正常に動作しない(図6)。

 この問題は、現在、

にも上がっており、その書き込みによるとバージョン「1.3.5-pre1」で修正される予定だそのバージョンで修正されたのを確認した)

図6 Windows Phoneでは、ScrollToメソッドが正常に動作しない
図6 Windows Phoneでは、ScrollToメソッドが正常に動作しない

6. テキストと画像のリストビュー

 テキストと画像のListViewビューを表示するには、App.csファイルを以下のように修正する。

C#
namespace ListViewSample{

  ……省略……

  internal class MyPage : ContentPage {

    class Data { // <-1
      public String Name { get; set; }
      public String Phone { get; set; }
      public String Icon { get; set; }
    }

    public MyPage() {

      var ar = new ObservableCollection<Data>();  // <-2
      ar.Add(new Data {Name = "Brent M. Soltis", Phone = "601-400-3356", Icon = "man.png"});
      ar.Add(new Data {Name = "Joel K. Coffey", Phone = "360-403-0486", Icon = "man.png"});
      ar.Add(new Data {Name = "Rhonda J. Bailey", Phone = "801-617-8209", Icon = "woman.png"});
      ar.Add(new Data {Name = "Elizabeth E. McClellan", Phone = "415-771-0336", Icon = "woman.png"});
      ar.Add(new Data {Name = "Michael H. White", Phone = "620-625-0916", Icon = "man.png"});


      // テンプレートの作成(ImageCell使用)
      var cell = new DataTemplate(typeof (ImageCell));        // <-3
      cell.SetBinding(ImageCell.TextProperty, "Name");        // <-4
      cell.SetBinding(ImageCell.DetailProperty, "Phone");     // <-5
      cell.SetBinding(ImageCell.ImageSourceProperty, "Icon"); // <-6

      // リストビューを生成する
      var listView = new ListView {
        ItemsSource = ar, 
        ItemTemplate = cell // <-7
      };

      Content = new StackLayout {
        Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0), // iOSのみ上部にマージンをとる
        Children = {listView}
      };
    }
  }
}
テキストと画像のリストビューを表示するコード(App.cs)

 サンプルでは、1つのセルに表示する情報を、「名前」「電話番号」「アイコン」の3種類とし、その1件のデータを表現するためのDataクラスを定義した(1)。

 続いて、Dataクラスを複数保持するための変数としてObservableCollection<Data>のインスタンスを生成し、いくつかのデータで初期化した(2)。

 ListViewビューに文字列以外を表示するためには、ItemTemplateプロパティにテンプレートを設定する必要がある。テンプレートには、DataTemplate型のインスタンスを指定するが、今回は組み込みのImageCellクラスを使用した(37)。

 ImageCellには、「上段のテキスト(=TextPropertyプロパティ)」「下段のテキスト(=DetailPropertyプロパティ)」「画像(=ImageSourcePropertyプロパティ)」の3つの表示箇所があり、それぞれをDataクラスのプロパティにバインディングした(456)。

 このコードを実行すると、次のようになる。

図7 テキストと画像のスクロールビュー(iOS) 図7 テキストと画像のスクロールビュー(Android)
図7 テキストと画像のスクロールビュー(iOS/Android)

 なお、使用する画像(本稿の例では「man.png」と「woman.png」)は、iOSの場合、「Resources」フォルダー、Androidの場合、「Resources/drawable」フォルダーにそれぞれ置かなければならない(図8)。

図8 画像ファイルの配置(iOS) 図8 画像ファイルの配置(Android)
図8 画像ファイルの配置(iOS/Android)

7. グループ表示

 先のテキストと画像のListViewビューをグループ化して表示するには、App.csファイルを以下のように修正する。

C#
namespace ListViewSample{

  ……省略……

  internal class MyPage : ContentPage {

    private class Data {
      public String Name { get; set; }
      public String Phone { get; set; }
      public String Icon { get; set; }
    }
    
    private class Group : ObservableCollection<Data> { // <-1
      public string Title { get; private set; } 
      public Group(string title) {
        Title = title;
      }
    }

    public MyPage() {

      var ar = new ObservableCollection<Group> { // <-2
        new Group("Man") {
          new Data {Name = "Brent M. Soltis", Phone = "601-400-3356", Icon = "man.png"},
          new Data {Name = "Joel K. Coffey", Phone = "360-403-0486", Icon = "man.png"},
          new Data {Name = "Michael H. White", Phone = "620-625-0916", Icon = "man.png"}
        },
        new Group("Woman") {
          new Data {Name = "Rhonda J. Bailey", Phone = "801-617-8209", Icon = "woman.png"},
          new Data {Name = "Elizabeth E. McClellan", Phone = "415-771-0336", Icon = "woman.png"},
        }
      };

      var cell = new DataTemplate(typeof (ImageCell));
      cell.SetBinding(ImageCell.TextProperty, "Name"); 
      cell.SetBinding(ImageCell.DetailProperty, "Phone"); 
      cell.SetBinding(ImageCell.ImageSourceProperty, "Icon");

      var listView = new ListView {
        ItemsSource = ar, 
        ItemTemplate = cell, 
        IsGroupingEnabled = true,  // <-3
        GroupDisplayBinding = new Binding("Title"),  // <-4
      };


      Content = new StackLayout {
        Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0), // iOSのみ上部にマージンをとる
        Children = {listView}
      };

    }
  }
}
グループ表示のリストビューを表示するコード(App.cs)

 Dataクラスをグループごとに表示するために、ObservableCollection<Data>クラスを継承したGroupクラスを定義する(1)。

 そして、このGroupクラスを複数保持するための変数としてObservableCollection<Group>のインスタンスを生成し、いくつかのデータで初期化した(2)。

 なお、グループ表示を有効にするには、IsGroupingEnabledプロパティにtrueを設定し(3)、GroupDisplayBinding(プロパティ)でグループのタイトルとなるプロパティをバインディングする必要がある(4)。

 このコードを実行すると、次のような画面になる。

図9 グループ表示のスクロールビュー(iOS) 図9 グループ表示のスクロールビュー(Android)
図9 グループ表示のスクロールビュー(iOS/Android)

8. まとめ

 今回は、ListViewビューについて、レンダラーを使用しないで軽易に利用できる範囲の使用方法を中心に解説した。

 セルのテンプレートにImageCell以外の組み込みセルを指定したり、自分で作成したテンプレートを使用したりする方法や、Xamarin.Formsのバージョン1.3で追加された、ContextActionの利用方法などについては、次回以降に解説したいと考えている。

※以下では、本稿の前後を合わせて5回分(第36回~第40回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

Xamarin逆引きTips
36. Xamarin.Formsでツールバーアイテムによるメニューを設置するには?

PageクラスのToolbarItemsプロパティを使って、画面の上部にツールバー(Android)/ナビゲーションバー(iOS)を表示する方法を解説する。

Xamarin逆引きTips
37. MvvmCrossのプロジェクトをセットアップするには?

クロスプラットフォーム開発を支援するXamarin用ライブラリの「MvvmCross」を使ってiOS/Androidアプリ開発を行うためのプロジェクトの作成方法を説明する。

Xamarin逆引きTips
38. 【現在、表示中】≫ Xamarin.FormsでListViewコントロールを使用するには?

データの一覧を表示できる「リストビュー」はXamarin.Formsでも提供されている。その基本的な使用方法を解説。また、セルの高さ指定/プログラムによるスクロール/画像表示などの方法も説明する。

Xamarin逆引きTips
39. Xamarin.Formsで地図を表示するには?(Xamarin.Forms.Maps使用)

Android/iOSアプリで各プラットフォーム標準の地図を表示するには、Xamarin.Forms.Mapsコントロールを使う。その基本的な使い方を説明する。

Xamarin逆引きTips
40. Xamarin.Formsで地図の現在位置やピンの表示、縮尺や地図タイプの変更を行うには?(Xamarin.Forms.Maps使用)

Xamarin.Forms.Mapsコントロールで利用可能な機能として、「現在位置」や「衛星写真」「ピン立て」「スライダーコントロールによる地図の拡大・縮小」などを解説する。

サイトからのお知らせ

Twitterでつぶやこう!