過去の記事の段階では色々と未実装機能が多かった .NET MAUI。2022/5/23についにリリースされましたので続きとして試してみました。※.NET MAUI を試すには Visual Studio 2022 v17.3 Preview 1.1 以降が必要です。
プロジェクト作成
インストール方法などはいくつも参考になる記事がでていましたので割愛します。
プロジェクトテンプレートが行方不明になる問題などもありましたが、ついに公式から正しい回避方法がでてました。global.json で sdk のバージョンを明示的に指定してからコマンドラインで作成しろとのことです。
global.jsonを以下の内容でプロジェクトを作成するフォルダに配置します。
{
"sdk": {
"version": "6.0.300",
"rollForward": "latestMinor"
}
}
コマンドラインで以下のコマンドを実行します。
dotnet new maui -n <プロジェクト名>
「テンプレート “.NET MAUI アプリ” が正常に作成されました。」と表示されれば成功です。Visual Studio 2022 v17.3 Preview 1.1以降で <プロジェクト名>.sln を開きます。
ついにエラーが無い状態でプロジェクトを開けました。
色々試してみる
クロスプラットフォームの動作確認
まずはそのままWindowsでデバッグ実行します。
Android (Emulator)でも試してみます。
共通のコードで動いています。素晴らしい。iPhone での動作確認は……まあいいでしょう。
.NET MAUI Shell アプリ
.NET MAUI Shell アプリという概念があるそうです。こちらによれば「.NET マルチプラットフォーム アプリ UI (.NET MAUI) シェルは、ほとんどのアプリで必要とされる基本的な機能を提供することで、アプリ開発の複雑さを軽減します。」ということだそうです。TabBar
, Tab
, FlyoutItem
, Shell.SearchHandler
などを使うとよく見るアプリのUIが簡単に作れるとのこと。これは便利そう。
まずはTab
で囲って元々あったShellContent
をコピペして貼り付けます。
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="MauiApp1.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MauiApp1"
Shell.FlyoutBehavior="Disabled">
<Tab>
<ShellContent
Title="Home"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage" />
<ShellContent
Title="Home"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage" />
</Tab>
</Shell>
タブが増えてます。カウントアップされていく [Click me] の数値がタブごとに独立しており、各ページがそれぞれ別のインスタンスになっていることが確認できます。
TabBar
を試してみます。わかりにくいのでHome1, Home2と表示名を変えました。
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="MauiApp1.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MauiApp1"
Shell.FlyoutBehavior="Disabled">
<TabBar>
<ShellContent
Title="Home1"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage" />
<ShellContent
Title="Home2"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage" />
</TabBar>
</Shell>
下部にタブができてます。Icon
を指定するとアイコンまで表示されるようです。
※公式には「1つの TabBar
オブジェクト内に複数の Tab
オブジェクトがある場合、Tab
オブジェクトは下部のタブとしてレンダリングされます。」とありましたが、コード例のようにTabBar
直下にShellContent
を並べないと下部のタブとしてレンダリングされませんでした。
Windowsで実行した場合はこんな感じ。
クロスプラットフォーム2D描画
恐らくあまり需要はありませんが、当社は地図を扱っているので描画系は試したくなります。今回はGraphicsViewを使った描画を試します。.NET MAUI では、Microsoft.Maui.Graphics
というクロスプラットフォームグラフィックスキャンバスが提供されています。
PaintPageという名称で .NET MAUI ContentPage (XAML) を追加し、AppShell.xaml で追加したページが表示されるように設定します。
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="MauiApp1.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MauiApp1"
Shell.FlyoutBehavior="Disabled">
<TabBar>
<ShellContent
Title="Home"
ContentTemplate="{DataTemplate local:MainPage}" />
<ShellContent
Title="Paint"
ContentTemplate="{DataTemplate local:PaintPage}" />
</TabBar>
</Shell>
2D描画にはGraphicsView
を使用します。GraphicsView
は描画されるコンテンツとしてIDrawable
の実装クラスを指定する必要があります。今回は黄色の矩形を描画する実装をしてみました。色の指定はICanvas.FillColor
などのICanvas
のプロパティで指定する仕様で、FillRectangle
にPen
やBrush
を指定できないのが少し気持ち悪いです。
public class GraphicsDrawable : IDrawable
{
public void Draw(ICanvas canvas, RectF dirtyRect)
{
canvas.FillColor = Colors.Yellow;
canvas.FillRectangle(100, 100, 100, 100);
}
}
次に PaintPage.xaml で描画用のリソースとして先程作成したGraphicsDrawable
を定義し、GraphicsViewのDrawable
に指定します。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MauiApp1"
x:Class="MauiApp1.PaintPage"
Title="PaintPage">
<ContentPage.Resources>
<local:GraphicsDrawable x:Key="drawable" />
</ContentPage.Resources>
<StackLayout>
<GraphicsView Drawable="{StaticResource drawable}"/>
</StackLayout>
</ContentPage>
おおお。穴の開いたポリゴンも試してみます。FillPath
にWindingMode.EvenOdd
を指定するのがポイントです。これを指定しないとPath
中の被った領域が全て塗りつぶされてしまいます。
public class GraphicsDrawable : IDrawable
{
public void Draw(ICanvas canvas, RectF dirtyRect)
{
var path = new PathF();
path.AppendRectangle(new RectF(100, 100, 150, 150));
path.AppendRectangle(new RectF(150, 150, 50, 50));
canvas.FillColor = Colors.Green;
canvas.FillPath(path, WindingMode.EvenOdd);
}
}
期待通り穴あきポリゴンを描画できました。Windowsでも確認します。
しっかり描画されていますね。ちなみに Windows ではGraphicsView
にHeightRequest
を定義してあげないと描画されませんでした。上画像の完全な xaml は以下になります。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MauiApp1"
x:Class="MauiApp1.PaintPage"
Title="PaintPage">
<ContentPage.Resources>
<local:GraphicsDrawable x:Key="drawable" />
</ContentPage.Resources>
<StackLayout>
<GraphicsView Drawable="{StaticResource drawable}"
HeightRequest="300"
WidthRequest="400"/>
</StackLayout>
</ContentPage>
念のためってことで実機として Google Pixel 6 Pro で試してみました。
しっかり動いています。ダークモードにも勝手に対応しています。
まとめ
まだ少し触った程度ではありますが、.NET MAUI は期待以上です。特に.NET MAUI Shell アプリが素晴らしい。よくあるUIで構成されたクロスプラットフォームアプリを作成する工数が大幅に短縮されそうです。2D描画については少し手間ですが簡単なものなら描画できそうです。SkiaSharpの方が良さげな気がしているので、今後はそちらも検証してみたいと思います。