.NET MAUI アプリにビジュアル コントロールを追加する

完了

.NET MAUI テンプレートを使用してアプリケーションを作成したので、次のステップでは、ユーザー インターフェイスを追加し、初期 UI ロジックを実装します。

このユニットでは、.NET MAUI (マルチプラットフォーム アプリケーション ユーザー インターフェイス) アプリケーションとナビゲーション構造の構成要素の詳細について説明します。

.NET MAUI プロジェクトの内容

まとめると、.NET MAUI プロジェクトには最初に次のものが含まれます。

  • MauiProgram.cs ファイル。アプリケーション オブジェクトを作成および構成するためのコードが含まれます。

  • App.xamlApp.xaml.cs ファイル。UI リソースを提供し、アプリケーションの初期ウィンドウを作成します。

  • アプリケーションの初期ページを指定し、ナビゲーション ルーティングのためにページの登録を処理する AppShell.xaml および AppShell.xaml.cs ファイル。

  • 初期ウィンドウに既定で表示されるページのレイアウトと UI ロジックを定義する MainPage.xaml および MainPage.xaml.cs ファイル。

必要に応じてさらにページをアプリに追加し、アプリに必要なビジネス ロジックを実装するための追加のクラスを作成できます。

.NET MAUI プロジェクトには、画像、アイコン、フォントなどのアプリケーション リソースの既定のセットと、各プラットフォームの既定のブートストラップ コードも含まれています。

Application クラス

App クラスは、.NET MAUI アプリケーション全体を表します。 それは、Microsoft.Maui.Controls.Application から既定の動作セットを継承します。 前のユニットで説明したように、ブートストラップ コードが各プラットフォームのためにインスタンスを作成し、読み込みを行うのは App クラスです。 次に、App クラスのコンストラクターは通常、AppShell クラスのインスタンスを作成して、それを MainPage プロパティに割り当てます。 このコードは、AppShell 内の定義に基づいてユーザーに表示される最初の画面を制御します。

App クラスには、次のものも含まれます。

  • アプリがいつバックグラウンドに送られるか (つまり、いつフォアグラウンド アプリでなくなるか) を含む、ライフサイクル イベントを処理するためのメソッド。

  • アプリケーション用に新しい Windows を作成するためのメソッド。 .NET MAUI アプリケーションは既定では単一ウィンドウとなりますが、さらに多くのウィンドウを作成して起動できます。これは、デスクトップやタブレット アプリケーションで役立ちます。

Shell

.NET Multi-platform App UI (.NET MAUI) Shell によって、ほとんどのアプリに必要な次のような基本機能が提供されて、アプリ開発の複雑さが軽減されます。

  • アプリのビジュアル階層を記述する 1 つの場所。
  • 一般的なナビゲーション ユーザー インターフェイス。
  • アプリ内の任意のページに移動できる URI ベースのナビゲーション方式。
  • 統合された検索ハンドラー

.NET MAUI Shell アプリでは、アプリのビジュアル階層は、Shell クラスをサブクラス化するクラス内に記述されます。 このクラスは、次の 3 つの主要な階層オブジェクトで構成できます。

  • FlyoutItem または TabBarFlyoutItem は、ポップアップ内の 1 つ以上のアイテムを表し、アプリのナビゲーション パターンでポップアップが必要な場合に使用するべきです。 TabBar は、下部のタブ バーを表し、アプリのナビゲーション パターンが下部のタブで始まり、ポップアップを必要としない場合に使用するべきです。
  • Tab。これは、下部のタブによって移動できるグループ化されたコンテンツを表します。
  • ShellContent は、各タブの ContentPage オブジェクトを表します。

これらのオブジェクトは、ユーザー インターフェイスを表すのではなく、アプリのビジュアル階層の編成を表します。 Shell はこれらのオブジェクトを取得し、コンテンツ用のナビゲーション ユーザー インターフェイスを生成します。

ページ

ページは、Shell の内部での .NET MAUI 内の UI 階層のルートです。 これまでに見たソリューションには、MainPage というクラスが含まれています。 このクラスは ContentPage から派生したもので、最も単純かつ最も一般的なページ タイプです。 コンテンツ ページにはそのコンテンツだけが表示されます。 .NET MAUI には、他にも次のような組み込みのページの種類がいくつかあります。

  • TabbedPage: タブ ナビゲーションに使用されるルート ページ。 タブ付きページには、タブごとに 1 つの子ページ オブジェクトが含まれています。

  • FlyoutPage:マスターと詳細スタイルのプレゼンテーションを実装できます。 ポップアップ ページには、項目の一覧が含まれています。 項目を選ぶと、その項目の詳細を含むビューが表示されます。

他にも使用できるページの種類があり、主にマルチスクリーン アプリでさまざまなナビゲーション パターンを有効にするために使われます。

Views

通常、コンテンツ ページにはビューが表示されます。 ビューを使うと、特定の方法でデータを取得して表示できます。 コンテンツ ページの既定のビューは ContentView であり、アイテムがそのまま表示されます。 ビューを縮小すると、ビューをサイズ変更するまで、アイテムが表示から消える場合があります。 ScrollView を使用すると、スクロール ウィンドウにアイテムを表示できます。ウィンドウを縮小した場合、上下にスクロールしてアイテムを表示できます。 CarouselView はスクロール可能なビューで、ユーザーはアイテムのコレクションをスワイプできます。 CollectionView は、名前付きのデータ ソースからデータを取得し、テンプレートをフォーマットとして使って各アイテムを表示できます。 他にも多くの種類のビューを使用できます。

コントロールとレイアウト

1 つのビューは、ボタン、ラベル、テキスト ボックスなどの 1 つのコントロールを含むことができます。 (厳密に言えば、ビュー自体がコントロールなので、ビューは別のビューを含むことができます。)ただし、1 つのコントロールに制限されたユーザー インターフェイスはあまり役に立たないため、コントロールはレイアウト内に配置されます。 レイアウトでは、コントロールが相互に相対的に表示されるルールを定義します。 レイアウトもコントロールであるため、ビューに追加できます。 既定の MainPage.xaml ファイルを見ると、このページ、ビュー、レイアウト、コントロールの階層の動作がわかります。 この XAML コードでは、VerticalStackLayout 要素は、他のコントロールのレイアウトを微調整できるようにするための 1 つのコントロールにすぎません。

<ContentPage ...>
    <ScrollView ...>
        <VerticalStackLayout>
            <Image ... />
            <Label ... />
            <Label ... />
            <Button ... />
        </VerticalStackLayout>
    </ScrollView>
</ContentPage>

レイアウトの定義に使われる一般的なコントロールとしては、次のものがあります。

  • VerticalStackLayoutHorizontalStackLayout は、上から下または左から右へのスタックでコントロールをレイアウトするように最適化されたスタック レイアウトです。 StackLayout も使用でき、これは Horizontal または Vertical に設定できる StackOrientation というプロパティを持ちます。 タブレットまたはスマートフォンでは、アプリケーションのコードでこのプロパティを変更すると、ユーザーがデバイスを回転させた場合に表示を調整できます。

    スタック レイアウトの横方向と縦方向によってコントロールがレイアウトされるしくみの図。

  • AbsoluteLayout を使うと、コントロールの正確な座標を設定できます。

  • FlexLayoutStackLayout と似ていますが、それに含まれる子コントロールが 1 つの行または列に収まらない場合に折り返せる点が異なります。 このレイアウトには、さまざまな画面サイズに合わせて配置および調整するためのオプションも用意されています。 たとえば、FlexLayout コントロールは、垂直配置されたとき、子コントロールを左、右、または中央揃えにすることができます。 水平配置のときは、均等な間隔になるようにコントロールを両端揃えできます。 水平の FlexLayoutScrollView の内側で使って、横方向にスクロールできる一連のフレームを表示できます (各フレーム自体には、垂直配置の FlexLayout を使用できます)。

    FlexLayout が画面にレンダリングされた状態で実行されているアプリのスクリーンショット。最初にイメージがレンダリングされ、次にタイトル、テキスト ラベル、ボタンが表示されます。これらの要素はすべて、ボックス内で垂直方向にレンダリングされます。

  • Grid では、設定した列と行の位置に従ってコントロールが配置されます。 列と行のサイズおよびスパンを定義できるので、グリッド レイアウトは必ずしも "チェッカーボードのような外観" とは限りません。

次の図は、これらの一般的なレイアウトの種類の主な属性をまとめたものです。

.NET MAUI UI で最も頻繫に使用されるレイアウトの図。

スタック レイアウトでは、垂直方向に配置された 4 つのボックスが表示されます。 絶対レイアウトでは、画面上の開発者が指定した場所に正確に配置された 4 つのボックスが表示されます。 Flex レイアウトでは、画面領域を最大限に活用するために画面にレイアウトされた複数のボックスが表示されます。 Grid レイアウトでは、画面にグリッド パターンでレイアウトされた複数のボックスが表示されます。

すべてのコントロールにはプロパティがあります。 これらのプロパティの初期値は、XAML (拡張アプリケーション マークアップ言語) を使用して設定できます。 多くの場合、これらのプロパティはアプリケーションの C# コードで変更できます。 たとえば、既定の .NET MAUI アプリの [Click me] ボタンの Clicked イベントを処理するコードは次のようになります。

int count = 0;
private void OnCounterClicked(object sender, EventArgs e)
{
    count+=5;

    if (count == 1)
        CounterBtn.Text = $"Clicked {count} time";
    else
        CounterBtn.Text = $"Clicked {count} times";

    SemanticScreenReader.Announce(CounterBtn.Text);
}

このコードは、ページ内の CounterBtn コントロールの Text プロパティを変更します。 コードでページ、ビュー、レイアウトの全体を作成することもできます。XAML を使う必要はありません。 たとえば、次のようなページの XAML 定義について考えてみます。

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Phoneword.MainPage">

    <ScrollView>
        <VerticalStackLayout>
            <Label Text="Current count: 0"
                Grid.Row="0"
                FontSize="18"
                FontAttributes="Bold"
                x:Name="CounterLabel"
                HorizontalOptions="Center" />

            <Button Text="Click me"
                Grid.Row="1"
                Clicked="OnCounterClicked"
                HorizontalOptions="Center" />
        </VerticalStackLayout>
    </ScrollView>
</ContentPage>

C# での同等のコードは次のようになります。

public partial class TestPage : ContentPage
{
    int count = 0;
    
    // Named Label - declared as a member of the class
    Label counterLabel;

    public TestPage()
    {       
        var myScrollView = new ScrollView();

        var myStackLayout = new VerticalStackLayout();
        myScrollView.Content = myStackLayout;

        counterLabel = new Label
        {
            Text = "Current count: 0",
            FontSize = 18,
            FontAttributes = FontAttributes.Bold,
            HorizontalOptions = LayoutOptions.Center
        };
        myStackLayout.Children.Add(counterLabel);
        
        var myButton = new Button
        {
            Text = "Click me",
            HorizontalOptions = LayoutOptions.Center
        };
        myStackLayout.Children.Add(myButton);

        myButton.Clicked += OnCounterClicked;

        this.Content = myScrollView;
    }

    private void OnCounterClicked(object sender, EventArgs e)
    {
        count++;
        counterLabel.Text = $"Current count: {count}";

        SemanticScreenReader.Announce(counterLabel.Text);
    }
}

C# コードはより冗長になりますが、UI を動的に調整できる柔軟性が増します。

アプリケーションの実行開始時にこのページを表示するには、AppShell でメインの ShellContent として TestPage クラスを設定します。

<ShellContent
        Title="Home"
        ContentTemplate="{DataTemplate local:TestPage}"
        Route="TestPage" />

レイアウトのチューニング

コントロールの周囲に少し "余裕" を持たせると便利です。 各コントロールは、レイアウトによって考慮される Margin プロパティを持ちます。 余白は、その他のものを押しやるコントロールと見なすことができます。

すべてのレイアウトには Padding プロパティもあり、どの子もレイアウトの境界にそれ以上近づくことはできません。 この概念の捉え方の 1 つは、すべてのコントロールが 1 つのボックスの中に入っていて、そのボックスは埋め込みをされた壁を持つというものです。

もう 1 つの便利な空白設定は、VerticalStackLayout または HorizontalStackLayoutSpacing プロパティです。 これはレイアウトのすべての子の間のスペースです。 この値はコントロール自体の余白に追加されるため、実際の空白は余白とスペースを加えたものになります。

知識チェック

1.

.NET MAUI のレイアウト型ではないものはどれですか?

2.

.NET MAUI で画面を作成するために使われるクラスは何ですか?