Xamarin逆引きTips
Xamarin.FormsでListViewコントロールを使用するには?
データの一覧を表示できる「リストビュー」はXamarin.Formsでも提供されている。その基本的な使用方法を解説。また、セルの高さ指定/プログラムによるスクロール/画像表示などの方法も説明する。
いろいろなアプリで比較的よく利用されるコントロールにリストビューがある。そして、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]ボタンを押す。
3. テキストのみのリストビュー
画面にテキストのみのListView
ビューを表示するには、App.csファイルを以下のように修正する。
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}
};
}
}
}
|
最初に、表示するデータを保持するためにString
型のObservableCollection
のインスタンスを生成し(1)、そこに100個のデータを追加した(2)。
続いて、ListView
ビューを生成し、そのItemsSource
プロパティに1で生成したデータをセットした(3)。
Content
プロパティには、まずは、StackLayout
のインスタンスを設定し、そのChildren
として、このListView
を配置した(4)。
このコードを実行すると、次のような画面になる。
4. セルの高さの指定
セルの高さを変更するには、App.csファイルを以下のように修正する。
namespace ListViewSample{
……省略……
internal class MyPage : ContentPage {
public MyPage() {
……省略……
var listView = new ListView {
ItemsSource = ar,
RowHeight = 30 // <-1
};
……省略……
}
}
}
|
ListView
クラスのRowHeight
プロパティには、セルの高さを設定できる(1)。
RowHeight
プロパティに30
や70
を指定した場合の画面は次のようになる。
【コラム】個別の高さ指定
セルの高さは個別に指定することもできるが、そのためには今回紹介できなかったカスタムセルを使用する必要がある。カスタムセルについては今後のTipsで詳しく解説する予定である。
5. スクロール
ListView
ビューのスクロールの動作を確認するために、App.csファイルを以下のように修正する。
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
}
};
}
}
|
最初に、データリストの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)。
このコードを実行して、ボタンをタップすると次のような画面になる。
なお、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. テキストと画像のリストビュー
テキストと画像のListView
ビューを表示するには、App.csファイルを以下のように修正する。
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}
};
}
}
}
|
サンプルでは、1つのセルに表示する情報を、「名前」「電話番号」「アイコン」の3種類とし、その1件のデータを表現するためのData
クラスを定義した(1)。
続いて、Data
クラスを複数保持するための変数としてObservableCollection<Data>
のインスタンスを生成し、いくつかのデータで初期化した(2)。
ListView
ビューに文字列以外を表示するためには、ItemTemplate
プロパティにテンプレートを設定する必要がある。テンプレートには、DataTemplate
型のインスタンスを指定するが、今回は組み込みのImageCell
クラスを使用した(37)。
ImageCell
には、「上段のテキスト(=TextProperty
プロパティ)」「下段のテキスト(=DetailProperty
プロパティ)」「画像(=ImageSourceProperty
プロパティ)」の3つの表示箇所があり、それぞれをData
クラスのプロパティにバインディングした(456)。
このコードを実行すると、次のようになる。
なお、使用する画像(本稿の例では「man.png」と「woman.png」)は、iOSの場合、「Resources」フォルダー、Androidの場合、「Resources/drawable」フォルダーにそれぞれ置かなければならない(図8)。
7. グループ表示
先のテキストと画像のListView
ビューをグループ化して表示するには、App.csファイルを以下のように修正する。
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}
};
}
}
}
|
Data
クラスをグループごとに表示するために、ObservableCollection<Data>
クラスを継承したGroup
クラスを定義する(1)。
そして、このGroup
クラスを複数保持するための変数としてObservableCollection<Group>
のインスタンスを生成し、いくつかのデータで初期化した(2)。
なお、グループ表示を有効にするには、IsGroupingEnabled
プロパティにtrueを設定し(3)、GroupDisplayBinding
(プロパティ)でグループのタイトルとなるプロパティをバインディングする必要がある(4)。
このコードを実行すると、次のような画面になる。
8. まとめ
今回は、ListView
ビューについて、レンダラーを使用しないで軽易に利用できる範囲の使用方法を中心に解説した。
セルのテンプレートにImageCell
以外の組み込みセルを指定したり、自分で作成したテンプレートを使用したりする方法や、Xamarin.Formsのバージョン1.3で追加された、ContextActionの利用方法などについては、次回以降に解説したいと考えている。
※以下では、本稿の前後を合わせて5回分(第36回~第40回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
36. Xamarin.Formsでツールバーアイテムによるメニューを設置するには?
PageクラスのToolbarItemsプロパティを使って、画面の上部にツールバー(Android)/ナビゲーションバー(iOS)を表示する方法を解説する。
37. MvvmCrossのプロジェクトをセットアップするには?
クロスプラットフォーム開発を支援するXamarin用ライブラリの「MvvmCross」を使ってiOS/Androidアプリ開発を行うためのプロジェクトの作成方法を説明する。
38. 【現在、表示中】≫ Xamarin.FormsでListViewコントロールを使用するには?
データの一覧を表示できる「リストビュー」はXamarin.Formsでも提供されている。その基本的な使用方法を解説。また、セルの高さ指定/プログラムによるスクロール/画像表示などの方法も説明する。
39. Xamarin.Formsで地図を表示するには?(Xamarin.Forms.Maps使用)
Android/iOSアプリで各プラットフォーム標準の地図を表示するには、Xamarin.Forms.Mapsコントロールを使う。その基本的な使い方を説明する。
40. Xamarin.Formsで地図の現在位置やピンの表示、縮尺や地図タイプの変更を行うには?(Xamarin.Forms.Maps使用)
Xamarin.Forms.Mapsコントロールで利用可能な機能として、「現在位置」や「衛星写真」「ピン立て」「スライダーコントロールによる地図の拡大・縮小」などを解説する。