かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Uno Platform でノッチとかに対応したい(セーフエリア)

iOS エミュレーターで動かすとノッチに食い込むテキストやボタンに悩まされる今日この頃。Uno Platform で対応する場合には Uno.UI.Toolkit.VisibleBoundsPadding クラスの PaddingMask プロパティでセーフエリアに入るように Padding を自動で調整することが出来ます。

例えば、ページ内のルートのレイアウトパネルに以下のように指定します。

<Page
    x:Class="App22.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="using:App22"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:toolkit="using:Uno.UI.Toolkit"
    mc:Ignorable="d">

    <RelativePanel toolkit:VisibleBoundsPadding.PaddingMask="All" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock
            x:Name="textBlockLabel"
            Margin="20"
            FontSize="30"
            Text="Hello, world!" />
        <Button
            x:Name="buttonOk"
            Margin="20,0"
            Click="ButtonOk_Click"
            Content="OK"
            FontSize="20"
            RelativePanel.Below="textBlockLabel" />
    </RelativePanel>
</Page>

これで上下左右にいい感じの余白が出来て画面内にコンテンツがおさまります。

指定あり

f:id:okazuki:20191226235328p:plain

指定なし

f:id:okazuki:20191226235519p:plain

UWP でビルドエラーになる

悲しいけどそのまま使うと UWP には Uno.UI への参照がないのでエラーになります。 そんな時はプラットフォーム固有の処理を XAML で書けるようになってるので、それを使います。

以下のような XML 名前空間を定義して ios, android, wasm は mc:Ignorable に突っ込みます。

xmlns:android="http://uno.ui/android"
xmlns:ios="http://uno.ui/ios"
xmlns:wasm="http://uno.ui/wasm"
xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
mc:Ignorable="d ios android wasm"

あとは、この名前空間をつけたタグや属性は、そのプラットフォーム以外では無視されます。今回のような添付プロパティは ios:toolkit:VisibleBoundsPadding.PaddingMask="All" のようには書けないので、以下のように Style に切り出すのがいいです。 ページのリソースなどに以下のような定義を足します。

<Page.Resources>
    <android:Style x:Key="PageStyle" TargetType="Grid">
        <Setter Property="toolkit:VisibleBoundsPadding.PaddingMask" Value="All" />
    </android:Style>
    <ios:Style x:Key="PageStyle" TargetType="Grid">
        <Setter Property="toolkit:VisibleBoundsPadding.PaddingMask" Value="All" />
    </ios:Style>
    <win:Style x:Key="PageStyle" TargetType="Grid" />
    <wasm:Style x:Key="PageStyle" TargetType="Grid" />
</Page.Resources>

そしてページのルートの Grid にこのスタイルを適用します。

<Grid Style="{StaticResource PageStyle}">

Style を android と ios のみの定義にして <Grid ios:Style="{StaticResource PageStyle}" android:Style="{StaticResource PageStyle}" .... のようにするのもありです。

こうすると iOS と Android でセーフエリアが適用されて UWP や WASM でもちゃんと動きます。

f:id:okazuki:20191227120736p:plain

追記

UWP のプロジェクトに Uno.UI のパッケージを追加する方法もあると教えてもらいました。