ListView

Browse sample. サンプルを参照する

.NET マルチプラットフォーム アプリ UI (.NET MAUI) ListView には、選択可能なデータ項目のスクロール可能な垂直リストが表示されます。 ListView がリストの外観を管理する一方で、リスト内の各項目の外観は、Cell を使用して項目を表示する DataTemplate によって定義されます。 .NET MAUI には、テキストと画像の組み合わせを表示するセルの種類が含まれており、必要なコンテンツを表示するカスタム セルを定義することもできます。 ListView には、ヘッダーとフッター、グループ化されたデータ、プルから更新、コンテキスト メニューの各項目の表示もサポートされています。

ListView クラスは ItemsView<Cell> クラスから派生し、次のプロパティを継承します。

  • IEnumerable 型の ItemsSource は、項目のコレクションが表示されるように指定します。既定値は null です。
  • DataTemplate 型の ItemTemplate は、表示される項目のコレクション内の各項目に適用するテンプレートを指定します。

ListView は次の特性を定義します。

  • object 型の Footer は、リストの末尾に表示される文字列またはビューを指定します。
  • DataTemplate 型の FooterTemplate は、Footer の書式設定に使用する DataTemplate を指定します 。
  • DataTemplate 型の GroupHeaderTemplate は、各グループのヘッダーの外観を定義するために使用する DataTemplate を定義します。 このプロパティと GroupDisplayBinding プロパティは、同時には有効にできません。 したがって、このプロパティを設定すると GroupDisplayBindingnull に設定されます。
  • bool 型の HasUnevenRows は、リスト内の項目に異なる高さの行を含めることができるかどうかを示します。 このプロパティの既定値は false です。
  • object 型の Header は、リストの先頭に表示される文字列またはビューを指定します。
  • DataTemplate 型の HeaderTemplate は、Header の書式設定に使用する DataTemplate を指定します 。
  • ScrollBarVisibility 型の HorizontalScrollBarVisibility は、 水平スクロール バーが表示されるタイミングを示します。
  • bool 型の IsGroupedEnabled は、基になるデータをグループに表示するかどうかを示します。 このプロパティの既定値は false です。
  • bool 型の IsPullToRefreshEnabled は、ユーザーが下にスワイプして ListView のデータを更新できるかどうかを示します。 このプロパティの既定値は false です。
  • bool 型の IsRefreshing は、ListView が現在更新されているかどうかを示します。 このプロパティの既定値は false です。
  • ICommand 型の RefreshCommand は、更新がトリガーされたときに実行されるコマンドを表します。
  • Color 型の RefreshControlColor は、更新の実行中に表示される更新視覚化の色を決定します。
  • int 型の RowHeight は、HasUnevenRowsfalse の場合の各行の高さを決定します。
  • object 型の SelectedItem は、ListView で現在選択されている項目を表します。
  • ListViewSelectionMode 型の SelectionMode は、ListView で項目を選択できるかどうかを示します。 このプロパティの既定値は Single です。
  • Color 型の SeparatorColor は、リスト 内の項目を区切るバーの色を定義します。
  • SeparatorVisibility 型の SeparatorVisibility は、アイテム間で区切り記号を表示するかどうかを定義します。
  • ScrollBarVisibility 型の VerticalScrollBarVisibility は、垂直スクロール バーが表示されるタイミングを示します。

これらのプロパティはすべて BindableProperty オブジェクトが基になっています。つまり、データ バインディングの対象にすることができ、スタイルを設定できます。

さらに、 ListView は、BindableProperty オブジェクトによってサポートされていない次のプロパティを定義します。

  • BindingBase 型の GroupDisplayBinding は、グループ ヘッダーの表示に使用するバインディングを取得または設定します。 このプロパティと GroupHeaderTemplate プロパティは、同時には有効にできません。 したがって、このプロパティを設定すると、GroupHeaderTemplatenull に設定されます。
  • BindingBase 型の GroupShortNameBinding は、グループ化されたジャンプ リストに表示する名前のバインドです。
  • ListViewCachingStrategyCachingStrategy は、ListView のセル再利用戦略を定義します 。 これは、読み取り専用プロパティです。

ListView では、次のイベントが定義されます。

  • ItemAppearing は、項目の視覚的な表現が、ListView の視覚的なレイアウトに追加されているときに発生します。 このイベントに付随する ItemVisibilityEventArgs オブジェクトは、ItemIndex プロパティを定義します。
  • ItemDisappearing は、項目の視覚的な表現が、ListView の視覚的なレイアウトから削除されているときに発生します。 このイベントに付随する ItemVisibilityEventArgs オブジェクトは、ItemIndex プロパティを定義します。
  • ItemSelected は、リストで新しい項目が選択されたときに発生します。 このイベントに付随する SelectedItemChangedEventArgs オブジェクトでは、SelectedItem プロパティと SelectedItemIndex プロパティが定義されています。
  • ItemTapped は、ListView 内の項目をタップしたときに発生します。 イベントに付随する ItemTappedEventArgs オブジェクトは、GroupItemItemIndex プロパティを定義します。
  • Refreshing は、ListView でプルして更新する操作がトリガーされたときに発生します。
  • Scrolled, . イベントに付随する ScrolledEventArgs オブジェクトは、ScrollXScrollY プロパティを定義します。
  • ScrollToRequested . このイベントに付随する ScrollToRequestedEventArgs オブジェクトは、ElementModePositionScrollXScrollYShouldAnimate のプロパティを定義します。

ListView にデータを読み込む

ListView にデータを読み込むには、IEnumerable を実装するコレクションに ItemsSource プロパティを設定します。

重要

基になるコレクションで項目を追加、削除、または変更するときに ListView を更新する必要がある場合、基になるコレクションは、ObservableCollection など、プロパティ変更通知を送信する IEnumerable コレクションである必要があります。

データ バインディングを使用して ItemsSource プロパティを IEnumerable コレクションにバインドすると、ListView にデータを設定できます。 XAML では、Binding マークアップ拡張を使用して実現できます。

<ListView ItemsSource="{Binding Monkeys}" />

同等の C# コードを次に示します。

ListView listView = new ListView();
listView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");

この例では、ItemsSource プロパティ データは接続したビューモデルの Monkeys プロパティにバインドします。

Note

コンパイル済みバインドを有効にして、.NET MAUI アプリケーションのデータ バインディングの性能を向上させることができます。 詳細については、「コンパイル済みのバインド」をご覧ください。

データ バインディングの詳細については、「データ バインディング」をご覧ください。

項目の外観を定義する

ListView の外観は、ItemTemplate プロパティを DataTemplate に設定することで定義できます。

<ListView ItemsSource="{Binding Monkeys}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Grid Padding="10">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <Image Grid.RowSpan="2"
                           Source="{Binding ImageUrl}"
                           Aspect="AspectFill"
                           HeightRequest="60"
                           WidthRequest="60" />
                    <Label Grid.Column="1"
                           Text="{Binding Name}"
                           FontAttributes="Bold" />
                    <Label Grid.Row="1"
                           Grid.Column="1"
                           Text="{Binding Location}"
                           FontAttributes="Italic"
                           VerticalOptions="End" />
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

DataTemplate で指定する要素は、リスト内の各項目の外観を定義し、DataTemplate の子は Cellオブジェクトである必要があります。 この例では、DataTemplate 内のレイアウトは Grid によって管理されています。 Grid には、1 つの Image オブジェクトと 2つの Label オブジェクトが含まれています。これらはすべて Monkey クラスのプロパティにバインドします。

public class Monkey
{
    public string Name { get; set; }
    public string Location { get; set; }
    public string Details { get; set; }
    public string ImageUrl { get; set; }
}

次のスクリーンショットは、リスト内の各項目をテンプレート化した結果を示しています。

Screenshot of ListView where each item is templated.

データ テンプレートの詳細については、「データ テンプレート」をご覧ください。

Cells

ListView 内の各項目の外観を DataTemplate で定義し、DataTemplateCell クラスを参照して項目を表示する必要があります。 各セルは、ListView でデータの項目を表します。 .NET MAUI には、次の組み込みセルが含まれています。

  • TextCell は、プライマリ テキストとセカンダリ テキストを別々の行に表示します。
  • ImageCell は、プライマリ テキストとセカンダリ テキストを別々の行で画像を表示します。
  • SwitchCell は、テキストと、オンとオフを切り替えることができるスイッチを表示します。
  • EntryCell は、編集可能なラベルとテキストを表示します。
  • ViewCell は、外観を View で定義するカスタム セルです。 このセルの種類は、ListView で各項目の外観を完全に定義するときに使用します。

通常は、SwitchCellEntryCellTableView でのみ使用し、ListView では使用しません。 SwitchCellEntryCell の詳細については、「TableView」をご覧ください。

テキストのセル

TextCell は、プライマリ テキストとセカンダリ テキストを別々の行に表示します。 TextCell は次の特性を定義します。

  • string 型の Text は、表示するプライマリ テキストを定義します。
  • Color 型の TextColor は、プライマリ テキストの色を表します。
  • string 型の Detail は、表示するセカンダリ テキストを定義します。
  • Color 型の DetailColor は、セカンダリ テキストの色を示します。
  • ICommand 型 の Command は、セルがタップされたときに実行するコマンドを定義します。
  • object 型の CommandParameter は、コマンドに渡されるパラメーターを表します。

これらのプロパティは、BindableProperty オブジェクトが基になっています。つまり、これらは、データ バインディングの対象にすることができ、スタイルを設定できます。

次の例は、TextCell を使用して ListView 内の項目の外観を定義する方法を示しています。

<ListView ItemsSource="{Binding Food}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <TextCell Text="{Binding Name}"
                      Detail="{Binding Description}" />
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

次のスクリーンショットは、結果のセルの外観を示しています。

Screenshot of ListView where each item is a TextCell.

イメージ セル

ImageCell では、プライマリ テキストとセカンダリ テキストを別々の行に含むイメージが表示されます。 ImageCell は、TextCell のプロパティを継承し、セルに表示するイメージを指定する ImageSource 型の ImageSource プロパティを定義します。 このプロパティは、BindableProperty オブジェクトが基になっています。つまり、データ バインディングの対象にすることができ、スタイルを設定できます。

次の例は ImageCell を使用して ListView の項目の外観を定義する方法を示しています。

<ListView ItemsSource="{Binding Food}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ImageCell ImageSource="{Binding Image}"
                       Text="{Binding Name}"
                       Detail="{Binding Description}" />
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

次のスクリーンショットは、結果のセルの外観を示しています。

Screenshot of ListView where each item is an ImageCell.

セルの表示

ViewCell は、外観が View によって定義されるカスタム セルです。 ViewCell は、セルの内容を表すビューを定義する、View 型の View プロパティを定義します。 このプロパティは、BindableProperty オブジェクトが基になっています。つまり、データ バインディングの対象にすることができ、スタイルを設定できます。

Note

View プロパティは ViewCell クラスのコンテンツ プロパティであるため、XAML から明示的に設定する必要はありません。

次の例は ViewCell を使用して ListView 内の項目の外観を定義する方法を示しています。

<ListView ItemsSource="{Binding Monkeys}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Grid Padding="10">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <Image Grid.RowSpan="2"
                           Source="{Binding ImageUrl}"
                           Aspect="AspectFill"
                           HeightRequest="60"
                           WidthRequest="60" />
                    <Label Grid.Column="1"
                           Text="{Binding Name}"
                           FontAttributes="Bold" />
                    <Label Grid.Row="1"
                           Grid.Column="1"
                           Text="{Binding Location}"
                           FontAttributes="Italic"
                           VerticalOptions="End" />
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

ViewCell 内では、レイアウトは任意の .NET MAUI レイアウトで管理できます。 この例では、レイアウトは Grid によって管理されています。 Grid には、Image オブジェクトと 2 つの Label オブジェクトが含まれており、これらすべてが Monkey クラスのプロパティにバインドします。

次のスクリーンショットは、リスト内の各項目をテンプレート化した結果を示しています。

Screenshot of ListView where each item is templated with a ViewCell.

実行時に項目の外観を選ぶ

ItemTemplate プロパティを DataTemplateSelector オブジェクトに設定すれば、項目の値に基づいて、実行時に ListView 内の各項目の外観を選択できます。

<ContentPage ...
             xmlns:templates="clr-namespace:ListViewDemos.Templates">
    <ContentPage.Resources>
        <DataTemplate x:Key="AmericanMonkeyTemplate">
            <ViewCell>
                ...
            </ViewCell>
        </DataTemplate>

        <DataTemplate x:Key="OtherMonkeyTemplate">
            <ViewCell>
                ...
            </ViewCell>
        </DataTemplate>

        <templates:MonkeyDataTemplateSelector x:Key="MonkeySelector"
                                             AmericanMonkey="{StaticResource AmericanMonkeyTemplate}"
                                             OtherMonkey="{StaticResource OtherMonkeyTemplate}" />
    </ContentPage.Resources>

    <StackLayout Margin="20">
        <ListView ItemsSource="{Binding Monkeys}"
                  ItemTemplate="{StaticResource MonkeySelector}" />
    </StackLayout>
</ContentPage>

ItemTemplate プロパティは、MonkeyDataTemplateSelector オブジェクトに設定されます。 次の例は、MonkeyDataTemplateSelector クラスを示しています。

public class MonkeyDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate AmericanMonkey { get; set; }
    public DataTemplate OtherMonkey { get; set; }

    protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
    {
        return ((Monkey)item).Location.Contains("America") ? AmericanMonkey : OtherMonkey;
    }
}

MonkeyDataTemplateSelector クラスは、異なるデータ テンプレートに設定される AmericanMonkeyOtherMonkeyDataTemplate プロパティを定義します。 OnSelectTemplate オーバーライドは AmericanMonkey テンプレートを返し、このテンプレートは、サルの名前に "America" が含まれている場合に、サルの名前と場所をティールで表示します。 サルの名前に "America" が含まれていない場合、OnSelectTemplate オーバーライドによって OtherMonkey テンプレートが返され、サルの名前と場所がシルバーで表示されます。

Screenshot of ListView runtime item template selection.

データ テンプレート セレクターの詳細については、「DataTemplateSelector の作成」をご覧ください。

項目の選択に応答する

既定では、ListView 選択は有効になっています。 ただし、この動作は、SelectionMode プロパティを設定すれば変更できます。 ListViewSelectionMode 列挙体を使って、次のメンバーを定義できます。

  • None – 項目が選択できないことを示します。
  • Single – 選択した項目が強調表示された状態で、1 つの項目を選択できることを示します。 これが既定値です。

ListView は、ユーザーがリストから項目を選択したため、またはアプリがプロパティを設定したことに伴い、SelectedItem プロパティが変更されたときに発生する ItemSelected イベントを定義します。 このイベントに付随する SelectedItemChangedEventArgs オブジェクトには、SelectedItemSelectedItemIndex のプロパティがあります。

SelectionMode プロパティが Single に設定されている場合は、ListView 内の 1 つの項目を選択できます。 項目が選択されると、SelectedItem プロパティは選択された項目の値に設定されます。 このプロパティが変更されると、ItemSelected イベントが発生します。

次の例は、1 つの項目の選択に応答できる ListView を示しています。

<ListView ItemsSource="{Binding Monkeys}"
          ItemSelected="OnItemSelected">
    ...
</ListView>

この例では、 OnItemSelected イベント ハンドラーは ItemSelected イベントが発生したときに実行され、イベント ハンドラーは選択した項目を取得します。

void OnItemSelected(object sender, SelectedItemChangedEventArgs args)
{
    Monkey item = args.SelectedItem as Monkey;
}

次のスクリーンショットは、ListView 内の 1 つの項目の選択を示しています。

Screenshot of a ListView with a selection.

選択のクリア

SelectedItem プロパティをクリアするには、このプロパティまたはこのプロパティのバインド先のオブジェクトを null に設定します。

選択を無効にする

ListView 選択は既定では有効になっています。 ただし、SelectionMode プロパティを None に設定すれば無効にできます。

<ListView ...
          SelectionMode="None" />

SelectionMode プロパティが None に設定されている場合、ListView 内の項目は選択できず、SelectedItem プロパティは null のままとなり、ItemSelected イベントは発生しません。

キャッシュ データ

ListView はデータを表示するための強力なビューですが、いくつかの制限があります。 カスタム セルを使用する場合、特に深く入れ子になったビュー階層が含まれている場合や、複雑な測定を必要とする特定のレイアウトを使用する場合、スクロールのパフォーマンスが低下する可能性があります。 ただし、 パフォーマンス低下を回避するために使用できる手法があります。

ListView は、多くの場合、画面に収まるよりも多くのデータを表示するために使用されます。 たとえば、音楽アプリには、何千ものエントリを含む曲のライブラリがある場合があります。 すべてのエントリに対して項目を作成すると、貴重なメモリが無駄になり、パフォーマンスが低下します。 行の作成と破棄を常に繰り返すと、アプリは常にオブジェクトのインスタンス化とクリーンアップを行う必要があり、パフォーマンスも低下します。

メモリを節約するために、各プラットフォームのネイティブ ListView に相当するものには、行を再利用するための機能が組み込まれています。 画面に表示されるセルのみがメモリに読み込まれ、コンテンツは既存のセルに読み込まれます。 このパターンにより、アプリが何千ものオブジェクトをインスタンス化することがなくなり、時間とメモリが節約されます。

.NET MAUI では、ListViewCachingStrategy 列挙を通じて ListView セルの再利用が許可されており、次の要素が定義されています。

  • RetainElement は、ListView がリスト内の項目ごとにセルを生成することを指定します。
  • RecycleElement は、ListView がリストのセルをリサイクルすることでメモリ占有領域と実行速度を最小限に抑えようとすることを指定します。
  • RecycleElementAndDataTemplate は、RecycleElement と同様に、ListViewDataTemplateSelector を使用する場合、DataTemplate オブジェクトがリスト内の項目のタイプごとにキャッシュされるようにします。

要素の保持

RetainElement キャッシュ戦略は、ListView がリスト内の項目ごとにセルを生成することを指定しており、これが既定の ListView 動作となります。 これは、次の状況で使用する必要があります。

  • 各セルには、多数のバインド (20 ~ 30 以上) がある。
  • セル テンプレートが頻繁に変更される。
  • テストの結果、RecycleElement のキャッシュ戦略では実行速度が低下することが判明した。

カスタム セルを使用する場合は、RetainElement キャッシュ戦略の結果を認識することが重要です。 セルの初期化コードは、セルの作成ごとに実行する必要があります。1 秒あたりに複数回実行できます。 この状況では、複数のネストされた StackLayout オブジェクトの使用など、ページ上では問題なかったレイアウト手法が、ユーザーのスクロールに合わせてリアルタイムで設定および破棄されると、パフォーマンスのボトルネックになってしまいます。

要素のリサイクル

RecycleElement キャッシング戦略では、ListView がメモリ占有領域と実行速度を最小限に抑えるためリストのセルをリサイクルするよう指定します。 このモードでは常にパフォーマンスが向上するとは限りません。テストを実行して改善点を特定する必要があります。 ただし、これは推奨される選択肢であり、次の状況で使用する必要があります。

  • 各セルには、少数から中程度の数のバインドがある。
  • 各セルの BindingContext が、すべてのセル データを定義している。
  • 各セルはほぼ類似しており、セルのテンプレートは変わらない。

仮想化中、セルのバインド コンテキストは更新されるため、アプリでこのモードを使用する場合は、バインド コンテキストの更新が適切に処理されるようにする必要があります。 セルに関するすべてのデータは、バインディング コンテキストから取得する必要があります。そうでない場合、整合性エラーが発生する可能性があります。 この問題は、データ バインディングを使用してセル データを表示することで回避できます。 または、次の例に示すように、カスタム セルのコンストラクターではなく、OnBindingContextChanged オーバーライドでセル データを設定する必要があります。

public class CustomCell : ViewCell
{
    Image image = null;

    public CustomCell()
    {
        image = new Image();
        View = image;
    }

    protected override void OnBindingContextChanged()
    {
        base.OnBindingContextChanged();

        var item = BindingContext as ImageItem;
        if (item != null)
        {
            image.Source = item.ImageUrl;
        }
    }
}

DataTemplateSelector を使用して要素をリサイクルする

ListViewDataTemplateSelector を使用して DataTemplate を選択する場合、RecycleElement キャッシュ戦略は DataTemplate オブジェクトをキャッシュしません。 代わりに、リスト内のデータの各項目に対して DataTemplate が選択されます。

Note

RecycleElement キャッシュ戦略では、DataTemplateSelectorDataTemplate を選択するように求められた場合、各 DataTemplate は同じ ViewCell 型を返す必要があります。 たとえば、MyDataTemplateA (MyDataTemplateAMyViewCellA 型の ViewCell を返す) または MyDataTemplateB (MyDataTemplateBMyViewCellB 型の ViewCell を返す) を返すことができる DataTemplateSelector を持つ ListView がある場合、MyDataTemplateA が返されたときは、MyViewCellA を返す必要があり、そうしないと例外がスローされます。

DataTemplates を使用して要素をリサイクルする

RecycleElementAndDataTemplate キャッシュ戦略は、RecycleElement キャッシュ戦略に基づいています。さらに、ListViewDataTemplateSelector を使用して DataTemplate を選択するときに、リスト内の項目の種類によって DataTemplate オブジェクトがキャッシュされることを保証しています。 そのため、DataTemplate オブジェクトは項目インスタンスごとに 1 回ではなく、項目の種類ごとに 1 回選択されます。

Note

RecycleElementAndDataTemplate キャッシュ戦略では、DataTemplateSelector によって返される DataTemplate オブジェクトは、Type を受け取る DataTemplate コンストラクターを使用する必要があります。

キャッシュ戦略の設定

ListView キャッシュ戦略は、XAML で CachingStrategy 属性を設定することで定義できます。

<ListView CachingStrategy="RecycleElement">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
              ...
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

C# では、キャッシュ戦略はコンストラクターのオーバーロードによって設定されます。

ListView listView = new ListView(ListViewCachingStrategy.RecycleElement);

サブクラス化された ListView でキャッシュ戦略を設定する

ListView には CachingStrategy プロパティがないため、サブクラス化された ListView に XAML から CachingStrategy 属性を設定しても、望ましい動作は得られません。 この問題の解決策は、ListViewCachingStrategy パラメーターを受け入れ、それを基本クラスに渡すサブクラス化された ListView でコンストラクターを指定することです。

public class CustomListView : ListView
{
    public CustomListView (ListViewCachingStrategy strategy) : base (strategy)
    {
    }
    ...
}

次に、ListViewCachingStrategy 列挙値は、x:Arguments 属性を使用して XAML から指定できます。

<local:CustomListView>
    <x:Arguments>
        <ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
    </x:Arguments>
</local:CustomListView>

ヘッダーとフッター

ListView では、リスト内の項目と共にスクロールするヘッダーとフッターを表示できます。 ヘッダーとフッターには、文字列、ビュー、または DataTemplate オブジェクトを指定できます。

ListView は、ヘッダーとフッターを指定するための次のプロパティを定義します。

  • object 型の Header は、リストの先頭に表示される文字列、バインド、またはビューを指定します。
  • DataTemplate 型の HeaderTemplate は、Header の書式設定に使用する DataTemplate を指定します 。
  • object 型の Footer は、リスト の末尾に表示される文字列、バインド、またはビューを指定します。
  • DataTemplate 型の FooterTemplate は、Footer の書式設定に使用する DataTemplate を指定します 。

これらのプロパティはすべて、BindableProperty オブジェクトを基にしています。つまり、プロパティをデータ バインディングの対象にすることができます。

次の例に示すように、Header プロパティと Footer プロパティは、string 値に設定することもできます。

<ListView ItemsSource="{Binding Monkeys}"
          Header="Monkeys"
          Footer="2022">
    ...
</ListView>

次のスクリーンショットは、結果のヘッダーを示しています。

Screenshot of a ListView string header.

Header プロパティと Footer プロパティはそれぞれビューに設定できます。 1 つのビュー、または複数の子ビューを含むビューを指定できます。 次の例は、Header プロパティと Footer プロパティが、それぞれ Label オブジェクトを含む StackLayout オブジェクトに設定されていることを示しています。

<ListView ItemsSource="{Binding Monkeys}">
    <ListView.Header>
        <StackLayout BackgroundColor="LightGray">
            <Label Margin="10,0,0,0"
                   Text="Monkeys"
                   FontSize="12"
                   FontAttributes="Bold" />
        </StackLayout>
    </ListView.Header>
    <ListView.Footer>
        <StackLayout BackgroundColor="LightGray">
            <Label Margin="10,0,0,0"
                   Text="Friends of Monkey"
                   FontSize="12"
                   FontAttributes="Bold" />
        </StackLayout>
    </ListView.Footer>
    ...
</ListView>

次のスクリーンショットは、結果のヘッダーを示しています。

Screenshot of CollectionView header and footer using views.

HeaderTemplate プロパティと FooterTemplate プロパティは、ヘッダーとフッターの書式設定に使用される DataTemplate オブジェクトに設定できます。 このシナリオでは、次の例に示すように、Header プロパティと Footer プロパティは、テンプレートが適用される現在のソースにバインドする必要があります。

<ListView ItemsSource="{Binding Monkeys}"
          Header="{Binding .}"
          Footer="{Binding .}">
    <ListView.HeaderTemplate>
        <DataTemplate>
            <StackLayout BackgroundColor="LightGray">
                <Label Margin="10,0,0,0"
                       Text="Monkeys"
                       FontSize="12"
                       FontAttributes="Bold" />
            </StackLayout>
        </DataTemplate>
    </ListView.HeaderTemplate>
    <ListView.FooterTemplate>
        <DataTemplate>
            <StackLayout BackgroundColor="LightGray">
                <Label Margin="10,0,0,0"
                       Text="Friends of Monkey"
                       FontSize="12"
                       FontAttributes="Bold" />
            </StackLayout>
        </DataTemplate>
    </ListView.FooterTemplate>
    ...
</ListView>

コントロール項目の区切り記号

既定では、iOS と Android では ListView 項目の間に区切り文字が表示されます。 この動作は、SeparatorVisibility タイプの SeparatorVisibility プロパティを None に設定することで変更できます。

<ListView ...
          SeparatorVisibility="None" />

さらに、区切り記号を有効にすると、SeparatorColor プロパティで色を設定できます。

<ListView ...
          SeparatorColor="Blue" />

アイテムのサイズを設定する

既定では、ListView 内のアイテムの高さはすべて同じです。この高さは、各アイテムの外観を定義する DataTemplate のコンテンツから派生しています。 ただし、この動作は、HasUnevenRows プロパティと RowHeight プロパティで変更できます。 デフォルトでは、HasUnevenRows プロパティは false です。

RowHeight プロパティは、HasUnevenRowsfalse である場合、ListView 内の各項目の高さを表す int に設定できます。 HasUnevenRowstrue に設定されている場合、ListView の各項目は異なる高さを持つことができます。 各項目の高さはアイテムの DataTemplate のコンテンツから派生するため、各項目はそのコンテンツに合わせてサイズ変更されます。

HasUnevenRows プロパティが true である場合、DataTemplate 内の要素のレイアウト関連プロパティを変更することで、個々の ListView アイテムのサイズを実行時にプログラムで変更できます。 次の例では、Image オブジェクトがタップされたときにその高さを変更します。

void OnImageTapped(object sender, EventArgs args)
{
    Image image = sender as Image;
    ViewCell viewCell = image.Parent.Parent as ViewCell;

    if (image.HeightRequest < 250)
    {
      image.HeightRequest = image.Height + 100;
      viewCell.ForceUpdateSize();
    }
}

この例では、OnImageTapped イベント ハンドラーは、Image オブジェクトがタップされたことに応答して実行されます。 イベント ハンドラーは Image の高さを更新し、Cell.ForceUpdateSize メソッドは現在表示されていない場合でもセルのサイズを更新します。

警告

動的な項目のサイズ設定を過度に使用すると、ListView のパフォーマンスが低下する可能性があります。

右から左へのレイアウト

ListView は、FlowDirection プロパティを RightToLeft に設定することで、コンテンツを右から左へのフロー方向にレイアウトできます。 ただし、FlowDirection プロパティは、ページまたはルート レイアウトに設定するのが理想的です。これにより、ページまたはルート レイアウト内のすべての要素がフローの方向に応答します。

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ListViewDemos.RightToLeftListPage"
             Title="Right to left list"
             FlowDirection="RightToLeft">
    <StackLayout Margin="20">
        <ListView ItemsSource="{Binding Monkeys}">
            ...
        </ListView>
    </StackLayout>
</ContentPage>

親を持つ要素の既定の FlowDirectionMatchParent です。 したがって、ListViewStackLayout から FlowDirection プロパティ値を継承し、さらに は ContentPage から FlowDirection プロパティ値を継承します。

グループ化されたデータを表示する

大規模なデータ セットは、スクロールし続けるリストで表示されると扱いにくくなることがよくあります。 このシナリオでは、データをグループにまとめることで、データの操作が容易になり、ユーザー エクスペリエンスが向上します。

データは、表示する前にグループ化する必要があります。 これは、グループのリストを作成することによって実現できます。ここで、各グループは項目のリストです。 グループのリストは IEnumerable<T> のコレクションである必要があります。T は 2 つのデータを定義します。

  • グループ名。
  • グループに属する項目を定義する IEnumerable コレクション。

したがって、データをグループ化するプロセスは次のとおりです。

  • 1 つの項目をモデル化する型を作成します。
  • 1 つの項目グループをモデル化する型を作成します。
  • IEnumerable<T> コレクションを作成します。T は 1 つの項目グループをモデル化する型です。 このコレクションは、グループ化されたデータを格納するグループのコレクションです。
  • IEnumerable<T> コレクションにデータを追加します。

データをグループ化する場合、最初の手順は、1 つの項目をモデル化する型を作成することです。 次の例は、Animal クラスを示しています。

public class Animal
{
    public string Name { get; set; }
    public string Location { get; set; }
    public string Details { get; set; }
    public string ImageUrl { get; set; }
}

Animal クラスは、1 つの項目をモデル化します。 その後、項目のグループをモデル化する型を作成できます。 次の例は、AnimalGroup クラスを示しています。

public class AnimalGroup : List<Animal>
{
    public string Name { get; private set; }

    public AnimalGroup(string name, List<Animal> animals) : base(animals)
    {
        Name = name;
    }
}

AnimalGroup クラスは List<T> クラスを継承し、グループ名を表す Name プロパティを追加します。

その後、グループの IEnumerable<T> コレクションを作成できます。

public List<AnimalGroup> Animals { get; private set; } = new List<AnimalGroup>();

このコードでは Animals という名前のコレクションを定義します。コレクション内の各項目は AnimalGroup オブジェクトです。 各 AnimalGroup オブジェクトは、名前と、グループ内の Animal オブジェクトを定義する List<Animal> コレクションで構成されます。

Animals コレクションにグループ化されたデータを追加できます。

Animals.Add(new AnimalGroup("Bears", new List<Animal>
{
    new Animal
    {
        Name = "American Black Bear",
        Location = "North America",
        Details = "Details about the bear go here.",
        ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/0/08/01_Schwarzbär.jpg"
    },
    new Animal
    {
        Name = "Asian Black Bear",
        Location = "Asia",
        Details = "Details about the bear go here.",
        ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b7/Ursus_thibetanus_3_%28Wroclaw_zoo%29.JPG/180px-Ursus_thibetanus_3_%28Wroclaw_zoo%29.JPG"
    },
    // ...
}));

Animals.Add(new AnimalGroup("Monkeys", new List<Animal>
{
    new Animal
    {
        Name = "Baboon",
        Location = "Africa & Asia",
        Details = "Details about the monkey go here.",
        ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Papio_anubis_%28Serengeti%2C_2009%29.jpg/200px-Papio_anubis_%28Serengeti%2C_2009%29.jpg"
    },
    new Animal
    {
        Name = "Capuchin Monkey",
        Location = "Central & South America",
        Details = "Details about the monkey go here.",
        ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Capuchin_Costa_Rica.jpg/200px-Capuchin_Costa_Rica.jpg"
    },
    new Animal
    {
        Name = "Blue Monkey",
        Location = "Central and East Africa",
        Details = "Details about the monkey go here.",
        ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/BlueMonkey.jpg/220px-BlueMonkey.jpg"
    },
    // ...
}));

このコードは、Animals コレクション内に 2 つのグループを作成します。 1 つ目の AnimalGroupBears という名前が付けられ 、クマの詳細の List<Animal> コレクションが含まれています。 2 つ目の AnimalGroupMonkeys という名前が付けられ、サルの詳細の List<Animal> コレクションが含まれています。

IsGroupingEnabled プロパティを true に設定すると、データが正しくグループ化されている場合は、ListView にグループ化されたデータが表示されます。

<ListView ItemsSource="{Binding Animals}"
          IsGroupingEnabled="True">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Grid Padding="10">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <Image Grid.RowSpan="2"
                           Source="{Binding ImageUrl}"
                           Aspect="AspectFill"
                           HeightRequest="60"
                           WidthRequest="60" />
                    <Label Grid.Column="1"
                           Text="{Binding Name}"
                           FontAttributes="Bold" />
                    <Label Grid.Row="1"
                           Grid.Column="1"
                           Text="{Binding Location}"
                           FontAttributes="Italic"
                           VerticalOptions="End" />
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

同等の C# コードを次に示します。

ListView listView = new ListView
{
    IsGroupingEnabled = true
};
listView.SetBinding(ItemsView.ItemsSourceProperty, "Animals");
// ...

ListView 内の各項目の外観は、その ItemTemplate プロパティを DataTemplate に設定して定義されます。 詳細については、「項目の外観を定義する」を参照してください。

次のスクリーンショットは、ListView にグループ化されたデータが表示されていることを示しています。

Screenshot of grouped data in a ListView.

Note

既定では、ListView はグループ ヘッダーにグループ名を表示します。 この動作は、グループ ヘッダーをカスタマイズすれば変更できます。

グループ ヘッダーをカスタマイズする

各グループ ヘッダーの外観は、 ListView.GroupHeaderTemplate プロパティを DataTemplate に設定すればカスタマイズできます。

<ListView ItemsSource="{Binding Animals}"
          IsGroupingEnabled="True">
    <ListView.GroupHeaderTemplate>
        <DataTemplate>
            <ViewCell>
                <Label Text="{Binding Name}"
                       BackgroundColor="LightGray"
                       FontSize="18"
                       FontAttributes="Bold" />
            </ViewCell>
        </DataTemplate>
    </ListView.GroupHeaderTemplate>
    ...
</ListView>

この例では、各グループ ヘッダーが Label に設定されており、そこには、グループ名が表示され、その他の外観プロパティが設定されています。 次のスクリーンショットは、カスタマイズされたグループ ヘッダーを示しています。

Screenshot of a customized group header in a ListView.

重要

GroupHeaderTemplate プロパティと GroupDisplayBinding プロパティは、同時には有効にできません。 したがって、両方のプロパティを設定しないでください。

テンプレートのないグループ

ListView は、ItemTemplate プロパティを DataTemplate に設定しなくても、グループ化されたデータを正しく表示できます。

<ListView ItemsSource="{Binding Animals}"
          IsGroupingEnabled="true" />

このシナリオでは、1 つの項目をモデル化する型の ToString メソッドと、1 つの項目グループをモデル化する型をオーバーライドして、意味のあるデータを表示できます。

スクロールを制御する

ListView は、項目をビューにスクロールする 2 つの ScrollTo メソッドを定義します。 オーバーロードの 1 つは指定した項目をビューにスクロールし、もう 1 つは指定したグループ内の指定した項目をビューにスクロールします。 どちらのオーバーロードにも、スクロールが完了した後のアイテムの正確な位置を指定し、スクロールをアニメーション化するかどうかを指定する追加の引数があります。

ListView は、ScrollToRequested メソッドのいずれかが呼び出されたときに発生する ScrollTo イベントを定義します。 ScrollToRequested イベントに付随する ScrollToRequestedEventArgs オブジェクトには、ShouldAnimateElementModePosition など、多くのプロパティがあります。 これらのプロパティの一部は、ScrollTo メソッド呼び出しで指定された引数から設定されます。

さらに、ListView では、スクロールが発生したことを示すために発生する Scrolled イベントを定義します。 Scrolled イベントに付随する ScrolledEventArgs オブジェクトには、ScrollXScrollY のプロパティがあります。

スクロールの検出

ListView は、スクロールが発生したことを示すために発生する Scrolled イベントを定義します。 Scrolled イベントに付随するオブジェクトを表す ItemsViewScrolledEventArgs クラスは、次のプロパティを定義します。

  • double 型の ScrollX は、スクロールの X 位置を表します。
  • double 型の ScrollY は、スクロールの Y 位置を表します。

次の XAML の例は、Scrolled イベントのイベント ハンドラーを設定する ListView を示しています。

<ListView Scrolled="OnListViewScrolled">
    ...
</ListView>

同等の C# コードを次に示します。

ListView listView = new ListView();
listView.Scrolled += OnListViewScrolled;

このコード例では、Scrolled イベントが発生したときに OnListViewScrolled イベント ハンドラーが実行されます。

void OnListViewScrolled(object sender, ScrolledEventArgs e)
{
    // Custom logic
}

重要

Scrolled イベントは、ユーザーが開始したスクロールと、プログラムによるスクロールに対して発生します。

項目をスクロールして表示する

ScrollTo メソッドは、指定された項目をビューにスクロールします。 listView という名前の ListView オブジェクトがある場合、次の例はテングザル (Proboscis Monkey) の項目をスクロールして表示する方法を示しています。

MonkeysViewModel viewModel = BindingContext as MonkeysViewModel;
Monkey monkey = viewModel.Monkeys.FirstOrDefault(m => m.Name == "Proboscis Monkey");
listView.ScrollTo(monkey, ScrollToPosition.MakeVisible, true);

または、項目とグループを指定することで、グループ化されたデータ内の項目をスクロールして表示することもできます。 次の例は、サル (Monkeys) グループのテングザル (Proboscis Monkey) 項目をスクロールして表示する方法を示しています。

GroupedAnimalsViewModel viewModel = BindingContext as GroupedAnimalsViewModel;
AnimalGroup group = viewModel.Animals.FirstOrDefault(a => a.Name == "Monkeys");
Animal monkey = group.FirstOrDefault(m => m.Name == "Proboscis Monkey");
listView.ScrollTo(monkey, group, ScrollToPosition.MakeVisible, true);

Note

ScrollToRequested イベントは、ScrollTo メソッドが呼び出されたときに発生します。

アニメーションのスクロールを無効にする

項目をスクロールして表示すると、スクロールするアニメーションが表示されます。 ただし、このアニメーションは、ScrollTo メソッドの animated 引数を false に設定することで無効にすることができます。

listView.ScrollTo(monkey, position: ScrollToPosition.MakeVisible, animate: false);

スクロール位置を制御する

項目をスクロールして表示する場合、スクロールが完了した後の項目の正確な位置は、ScrollTo メソッドの position 引数を使用して指定できます。 この引数は ScrollToPosition 列挙要素を受け入れます。

MakeVisible

ScrollToPosition.MakeVisible 要素は、ビューに表示されるまで項目をスクロールする必要があることを示します。

listView.ScrollTo(monkey, position: ScrollToPosition.MakeVisible, animate: true);

先頭

ScrollToPosition.Start 要素は、項目をビューの先頭までスクロールする必要があることを示します。

listView.ScrollTo(monkey, position: ScrollToPosition.Start, animate: true);

中央

ScrollToPosition.Center 要素は、項目をビューの中央までスクロールする必要があることを示します。

listView.ScrollTo(monkey, position: ScrollToPosition.Center, animate: true);

末尾

ScrollToPosition.End 要素は、項目をビューの末尾までスクロールする必要があることを示します。

listView.ScrollTo(monkey, position: ScrollToPosition.End, animate: true);

スクロール バーの表示

ListView は、バインド可能なプロパティによってサポートされる HorizontalScrollBarVisibility プロパティと VerticalScrollBarVisibility プロパティを定義します。 これらのプロパティは、水平スクロール バーまたは垂直スクロール バーが表示されるタイミングを表す ScrollBarVisibility 列挙値を取得または設定します。 ScrollBarVisibility 列挙体を使って、次のメンバーを定義できます。

  • Default は、プラットフォームの既定のスクロール バーの動作を示し、HorizontalScrollBarVisibility プロパティおよび VerticalScrollBarVisibility プロパティの既定値です。
  • Always は、コンテンツがビューに収まる場合でもスクロール バーが表示されることを示します。
  • Never は、コンテンツがビューに収まらない場合でもスクロール バーが表示されないことを示します。

コンテキスト メニューを追加する

ListView は、コンテキスト メニュー項目をサポートします。これは、各項目の DataTemplate 内の ViewCell.ContextActions コレクションに追加される MenuItem オブジェクトとして定義されます。

<ListView x:Name="listView"
          ItemsSource="{Binding Monkeys}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <ViewCell.ContextActions>
                    <MenuItem Text="Favorite"
                              Command="{Binding Source={x:Reference listView}, Path=BindingContext.FavoriteCommand}"
                              CommandParameter="{Binding}" />
                    <MenuItem Text="Delete"
                              Command="{Binding Source={x:Reference listView}, Path=BindingContext.DeleteCommand}"
                              CommandParameter="{Binding}" />
                </ViewCell.ContextActions>

                ...
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

ListView 内の項目を右クリックすると、MenuItem オブジェクトが表示されます。

Screenshot of CollectionView context menu items.

メニュー項目の詳細については、「メニュー項目の表示」を参照してください。

引っ張って更新

ListView は、引っ張って更新する機能をサポートしています。これにより、項目のリストをプルダウンすることで、表示されているデータを更新できます。

引っ張って更新する機能を有効にするには、IsPullToRefreshEnabled プロパティを true に設定します。 更新がトリガーされると、ListView によって Refreshing イベントが発生し、IsRefreshing プロパティが true に設定されます。 ListView のコンテンツを更新するために必要なコードは、Refreshing イベントのハンドラーによって実行されるか、RefreshCommand が実行する ICommand 実装によって実行される必要があります。 ListView が更新されたら、IsRefreshing プロパティを false に設定するか、ListViewEndRefresh メソッドを呼び出して、更新が完了したことを示す必要があります。

次の例は、引っ張って更新する機能を使用する ListView を示しています。

<ListView ItemsSource="{Binding Animals}"
          IsPullToRefreshEnabled="true"
          RefreshCommand="{Binding RefreshCommand}"
          IsRefreshing="{Binding IsRefreshing}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                ...
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

この例では、ユーザーが更新を開始すると、RefreshCommand プロパティによって定義された ICommand が実行され、表示されている項目が更新されます。 更新が行われると、アニメーション化された進行状況の円で構成される更新の視覚化が表示されます。 IsRefreshing プロパティの値は、更新操作の現在の状態を示しています。 更新がトリガーされると、このプロパティは自動的に true に遷移します。 更新が完了したら、プロパティを false にリセットする必要があります。