kamulog

xamarin.formsのネタなど

Xamarin.Forms Guides「iOS Platform-Specifics」の日本語訳(の練習)

https://developer.xamarin.com/guides/xamarin-forms/platform-features/platform-specifics/consuming/ios/ 2018年2月5日時点の翻訳です。

注意事項

  • 基本的に直訳で意訳はあまりしません。
  • あくまで英語のReadingの練習であり、嘘率は高いです。
  • 今回長すぎたので原文引用は省略しています。

iOS Platform-Specifics

Platform-specificsはcustom renderersやeffectsを実装することなく、特定のプラットフォーム上でのみ利用できる機能を使用することを可能にします。この記事ではXamarin.Formsに組み込み済みのiOSのplatform-specificsの使い方について説明します。

iOSではXamarin.Formsは以下のようなplatform-specificsがあります。

Applying Blur

このplatform-specificは下に重なったコンテンツをぼかすために使われ、XamlでVisualElement.BlurEffectという添付プロパティにBlureEffectStyleのenum値を設定することによって使用します。

<ContentPage ...
             xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
  ...
  <AbsoluteLayout HorizontalOptions="Center">
    <Image Source="monkeyface.png" />
    <BoxView x:Name="boxView" ios:VisualElement.BlurEffect="ExtraLight" HeightRequest="300" WidthRequest="300" />
  </AbsoluteLayout>
  ...
</ContentPage>

あるいは、C#でfluent API*1を使って使用します。

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

boxView.On<iOS>().UseBlurEffect(BlurEffectStyle.ExtraLight);

BoxView.On<iOS>メソッドは、このplatform-specificがiOSでのみ実行されることを指定します。VisualElement.UseBlurEffectメソッドは、Xamarin.Forms.PlatformConfiguration.iOSSpecific名前空間の中にあり、BlurEffectStyle列挙型が提供する4つの値(None, ExtraLight, Light, Dark)を使ってぼかし効果を適用するために使います。

結果として、指定されたBlurEffectStyleがBoxViewのインスタンスに適用され、下に重なっているImageをぼかします。

(結果は元ページの画像を参照してください)

Displaying Large Titles

このplatform-specificは、iOS11以上を使うデバイスで、ナビゲーションバーのlarge titleとしてページタイトルを表示するために使われます。large titleは左寄せで大きいフォントが使われます。そして画面の領域を効率的に使うために、ユーザーがコンテンツをスクロールした時に、標準のタイトルに移り変わります。しかし横向きの画面では、コンテンツのレイアウトを最適化するためにタイトルはナビゲーションバーの中央に戻ります。この機能はXamlでNavigationPage.PrefersLargeTitles添付プロパティにbool値を設定することで使用します。

<NavigationPage xmlns="http://xamarin.com/schemas/2014/forms"
                xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
                ...
                ios:NavigationPage.PrefersLargeTitles="true">
  ...
</NavigationPage>

あるいはC#でfluent APIを使って使用します。

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

var navigationPage = new Xamarin.Forms.NavigationPage(new iOSLargeTitlePageCS());
navigationPage.On<iOS>().SetPrefersLargeTitles(true);

NavigationPage.On<iOS>メソッドはこのplatform-specificがiOS上でだけ動作することを指定します。NavigationPage.SetPrefersLargeTitleメソッドは、Xamarin.Forms.PlatformConfiguration.iOSSpecific名前空間に存在し、large titlesを有効にするかどうかの制御をします。

NavigationPageでlarge titlesが有効にすると、ナビゲーションスタックにある全てのページはlarge titlesを表示するようになります。この振る舞いは個々のページ上でPage.LargeTitleDisplay添付プロパティにLargeTitleDisplayModeの列挙値を指定することで上書きできます。

<ContentPage ...
             xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
             Title="Large Title"
             ios:Page.LargeTitleDisplay="Never">
  ...
</ContentPage>

あるいはfluent APIを使ってC#からそのページの振る舞いを上書きできます。

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

public class iOSLargeTitlePageCS : ContentPage
{
    public iOSLargeTitlePageCS(ICommand restore)
    {
        On<iOS>().SetLargeTitleDisplay(LargeTitleDisplayMode.Never);
        ...
    }
    ...
}

Page.On<iOS>メソッドはこのplatform-specificがiOS上でのみ動作することを指定します。Page.SetLargeTitleDisplayメソッドは、Xamarin.Forms.PlatformConfiguration.iOSSpecific名前空間に存在し、ページ上のlarge titleを3つの値持つLargeTitleDisplayMode列挙型で制御します。

  • Always - 強制的にナビゲーションバーとフォントサイズに大きいフォーマットを使う
  • Automatic - ナビゲーションスタックの前の要素と同じスタイル(largeかsmall)を使う
  • Never - 標準を強制し、小さいフォーマットのナビゲーションバーにする

さらに、SetLargeTitleDisplayメソッドは、現在のLargeTitleDisplayModeを返すLargeTitleDisplayメソッドを呼ぶことで列挙値を切り替えて使うことができます。

switch (On<iOS>().LargeTitleDisplay())
{
    case LargeTitleDisplayMode.Always:
        On<iOS>().SetLargeTitleDisplay(LargeTitleDisplayMode.Automatic);
        break;
    case LargeTitleDisplayMode.Automatic:
        On<iOS>().SetLargeTitleDisplay(LargeTitleDisplayMode.Never);
        break;
    case LargeTitleDisplayMode.Never:
        On<iOS>().SetLargeTitleDisplay(LargeTitleDisplayMode.Always);
        break;
}

その結果、指定したLargeTitleDisplayModeがページに適用され、large titleの振る舞いを制御します。

(結果は元ページの画像を参照してください)

Enabling the Safe Area Layout Guide

このplatform-specificはiOS11以上を使う全てのデバイスでページコンテンツを安全な画面の領域に配置させるために使います。特に、iPhone Xでデバイスの角丸やホームインジケータやセンサーハウジングによってコンテンツが切り抜かれないようにすることを助けます。これはXamlでPage.UseSafeArea添付プロパティにブール値を設定することで使用します。

<ContentPage ...
             xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
             Title="Safe Area"
             ios:Page.UseSafeArea="true">
    <StackLayout>
        ...
    </StackLayout>
</ContentPage>

あるいは、C#のfluent APIを使って使用します。

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

On<iOS>().SetUseSafeArea(true);

Page.On<iOS>メソッドは、このplatform-specificがiOS上でのみ動作することを指定します。Page.SetUseSafeAreaメソッドはXamarin.Forms.PlatformConfiguration.iOSSpecific名前空間に存在し、セーフエリアのレイアウトガイドを有効にするかどうかを制御します。

その結果、ページコンテンツを全てのiPhoneで画面上の安全なエリアに配置することができます。

(結果は元ページの画像を参照してください)

注意:Appleによって定義されたセーフエリアは、Xamarin.FormsではPage.Paddingプロパティの設定が使用されます。既にセットされたこのプロパティの全ての値は上書きされます。

セーフエリアはXamarin.Forms.PlatformConfiguration.iOSSpecific名前空間のPage.SafeAreaInsetsメソッドを使って、そのThicknessの値を変更することでカスタマイズが可能です。取得したThickness値を必要に応じて、ページのコンストラクタやOnAppearingのオーバーライドで、Paddingプロパティに再割り当てすることで変更が可能です。

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

    var safeInsets = On<iOS>().SafeAreaInsets();
    safeInsets.Left = 20;
    Padding = safeInsets;
}

Making the Navigation Bar Translucent

このplatform-specificはナビゲーションバーの透明度を変更するために使われます。XamlではNavigationPage.IsNavigationBarTranslucent添付プロパティにbool値を設定して使用します。

<NavigationPage ...
                xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
                BackgroundColor="Blue"
                ios:NavigationPage.IsNavigationBarTranslucent="true">
  ...
</NavigationPage>

あるいはC#でfluent APIを使って使用します。

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

(App.Current.MainPage as Xamarin.Forms.NavigationPage).BackgroundColor = Color.Blue;
(App.Current.MainPage as Xamarin.Forms.NavigationPage).On<iOS>().EnableTranslucentNavigationBar();

NavigationPage.On<iOS>メソッドはiOS上でのみ実行することを指定します。NavigationPage.EnableTranslucentNavigationBarメソッドは、Xamarin.Forms.PlatformConfiguration.iOSSpecific名前空間に存在し、ナビゲーションバーを透過させるために使用されます。さらに、Xamarin.Forms.PlatformConfiguration.iOSSpecific名前空間のNavigationPageクラスには、ナビゲーションバーをデフォルトの状態に戻すDisableTranslucentNavigationBarメソッドやIsNavigationBarTranslucentを呼ぶことでナビゲーションバーの透明度を切り替えるために使うことができるSetIsNavigationBarTranslucentメソッドもあります。

(App.Current.MainPage as Xamarin.Forms.NavigationPage)
  .On<iOS>()
  .SetIsNavigationBarTranslucent(!(App.Current.MainPage as Xamarin.Forms.NavigationPage).On<iOS>().IsNavigationBarTranslucent());

その結果、ナビゲーションバーの透明度を変更することができます。

(結果は元ページの画像を参照してください)

Adjusting the Status Bar Text Color Mode

このplatform-specificはNavigationPageのステータスバーのテキスト色をナビゲーションバーの明るさに合うように調整するかどうかを制御します。XamlではNavigationPage.StatusBarTextColorMode添付プロパティにStatusBarTextColorMode列挙値を指定して使用します。

<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
    x:Class="PlatformSpecifics.iOSStatusBarTextColorModePage">
    <MasterDetailPage.Master>
        <ContentPage Title="Master Page Title" />
    </MasterDetailPage.Master>
    <MasterDetailPage.Detail>
        <NavigationPage BarBackgroundColor="Blue" BarTextColor="White"
                        ios:NavigationPage.StatusBarTextColorMode="MatchNavigationBarTextLuminosity">
            <x:Arguments>
                <ContentPage>
                    <Label Text="Slide the master page to see the status bar text color mode change." />
                </ContentPage>
            </x:Arguments>
        </NavigationPage>
    </MasterDetailPage.Detail>
</MasterDetailPage>

あるいは、C#でfluent APIを使って使用します。

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

IsPresentedChanged += (sender, e) =>
{
    var mdp = sender as MasterDetailPage;
    if (mdp.IsPresented)
        ((Xamarin.Forms.NavigationPage)mdp.Detail)
          .On<iOS>()
          .SetStatusBarTextColorMode(StatusBarTextColorMode.DoNotAdjust);
    else
        ((Xamarin.Forms.NavigationPage)mdp.Detail)
          .On<iOS>()
          .SetStatusBarTextColorMode(StatusBarTextColorMode.MatchNavigationBarTextLuminosity);
};

NavigationPage.On<iOS>メソッドはこのplatform-specificがiOS上でのみ実行するように指定します。NavigationPage.SetStatusBarTextColorModeメソッドは、Xamarin.Forms.PlatformConfiguration.iOSSpecific名前空間に存在し、NavigationPageのステータスバーのテキスト色をナビゲーションバーの明るさに合うように調整するかどうかをStatusBarTextColorMode列挙型が提供する2つの値を使って制御します。

  • DoNotAdjust - ステータスバーのテキスト色を調整しないことを指定。
  • MatchNavigationBarTextLuminosity - ステータスバーのテキスト色をナビゲーションバーの明るさに合わせることを指定。

さらにGetStatusBarTextColorModeメソッドはNavigationPageに適用された現在のStatusBarTextColorMode列挙値を取得するために使います。

その結果、NavigationPageのステータスバーのテキスト色はナビゲーションバーの明るさに合わせて調整されます。この例では、ステータスバーのテキスト色はMasterDetailPageのMasterとDetailをユーザが切り替えたときに変化します。

(結果は元ページの画像を参照してください)

Adjusting the Font Size of an Entry

このplatform-specificは、Entryのフォントサイズを、入力テキストがそのコントロール内にフィットするように拡大縮小するために使われます。XamlではEntry.AdjustsFontSizeToFitWidth添付プロパティにbool値を指定して使用します。

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage ...
             xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
    <StackLayout Margin="20">
        <Entry x:Name="entry"
               Placeholder="Enter text here to see the font size change"
               FontSize="22"
               ios:Entry.AdjustsFontSizeToFitWidth="true" />
        ...
    </StackLayout>
</ContentPage>

あるいはC#でfluent APIを使って使用します。

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

entry.On<iOS>().EnableAdjustsFontSizeToFitWidth();

Entry.On<iOS>メソッドはこのplatform-specificがiOS上でのみ実行することを指定します。Entry.EnableAdjustsFontSizeToFitWidthメソッドは、Xamarin.Forms.PlatformConfiguration.iOSSpecific名前空間に存在し、入力テキストのフォントサイズをEntryにフィットさせるように拡大縮小するために使用します。さらにXamarin.Forms.PlatformConfiguration.iOSSpecific名前空間のEntryクラスには、このplatform-specificを無効にするDisableAdjustsFontSizeToFitWidthメソッドや、AdjustsFontSizeToFitWidthメソッドを呼ぶことでフォントサイズの拡大縮小を切り替えるために使うSetAdjustsFontSizeToFitWidthメソッドもあります。

entry.On<iOS>().SetAdjustsFontSizeToFitWidth(!entry.On<iOS>().AdjustsFontSizeToFitWidth());

その結果、Entryのフォントサイズは入力テキストがコントロール内にフィットするように拡大縮小されます。

(結果は元ページの画像を参照してください)

Controlling Picker Item Selection

このplatform-specificは、Pickerでのitem selectionの発生するタイミングを制御し、ユーザーがPicker内でアイテムを動かしている時にitem selectionを発生させるか、Doneボタンを押した時に1度だけ発生させるかの指定を可能にします。XamlではPicker.UpdateMode添付プロパティにUpdateMode列挙型の値を設定して使用します。

<ContentPage ...
             xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
    <StackLayout Margin="20">
        <Picker ... Title="Select a monkey" ios:Picker.UpdateMode="WhenFinished">
          ...
        </Picker>
        ...
    </StackLayout>
</ContentPage>

あるいは、C#でfluent APIを使って使用します。

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

picker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);

Picker.On<iOS>メソッドはこのplatform-specificがiOS上でのみ動作することを指定します。Picker.SetUpdateModeメソッドは、Xamarin.Forms.PlatformConfiguration.iOSSpecific名前空間に存在し、UpdateMode列挙型が提供する2つの値を使って、item selectionが発生するタイミングを制御をするために使用されます。

  • Immediately - Pickerでユーザーがアイテムを動かしているときにitem selectionが発生します。これはXamarin.Formsのdefaultの動作です。
  • WhenFinished - PickerでユーザーがDoneボタンを押した時に1回だけitem selectionが発生します。

さらに、SetUpdateModeメソッドは、現在のUpdateModeを返すUpdateModeメソッドを呼んで列挙値を切り替えることに使用できます。

switch (picker.On<iOS>().UpdateMode())
{
    case UpdateMode.Immediately:
        picker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
        break;
    case UpdateMode.WhenFinished:
        picker.On<iOS>().SetUpdateMode(UpdateMode.Immediately);
        break;
}

その結果、Pickerに指定されたUpdateModeが適用され、item selectionが発生するタイミングを制御します。

(結果は元ページの画像を参照してください)

Setting the Status Bar Visibility on a Page

このplatform-specificはページのステータスバーの可視性を設定するために使用されます。これにはステータスバーがどのようにページに出入りするのかを制御する能力を含みます。XamlではPage.PrefersStatusBarHidden添付プロパティにStatusBarHiddenMode列挙型の値を設定して使用します。そして任意でPage.PreferredStatusBarUpdateAnimation添付プロパティにUIStatusBarAnimation列挙型の値を設定します。

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage ...
             xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
             ios:Page.PrefersStatusBarHidden="True"
             ios:Page.PreferredStatusBarUpdateAnimation="Fade">
  ...
</ContentPage>

あるいはC#からfluent APIを使って使用します。

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

On<iOS>().SetPrefersStatusBarHidden(StatusBarHiddenMode.True)
         .SetPreferredStatusBarUpdateAnimation(UIStatusBarAnimation.Fade);

Page.On<iOS>メソッドはこのplatform-specificがiOS上でのみ動作することを指定します。Page.SetPrefersStatusBarHiddenメソッドは、Xamarin.Forms.PlatformConfiguration.iOSSpecific名前空間に存在し、StatusBarHiddenMode列挙型の値(Default / True / False)の一つを指定することでページ上のステータスバーの可視性を設定するために使用されます。StatusBarHiddenMode.TrueとStatusBarHiddenMode.Falseはデバイスの向きに関係なくステータスバーの可視性を設定します。そしてStatusBarHiddenMode.Defaultは縦向きの小さい環境でステータスバーを隠します。

その結果、ページのステータスバーの可視性がセットされます。

(結果は元ページの画像を参照してください)

TabbedPageでは、指定されたStatusBarHiddenMode列挙型の値は、全ての子ページのステータスバーも更新します。Page型を継承した他の全ての型では、指定されたStatusBarHiddenModeの値は現在のページのステータスバーのみを更新します。

Page.SetPreferredStatusBarUpdateAnimationメソッドはステータスバーがどのようにしてページに出入りするのかをUIStatusBarAnimation列挙型の値(None / Fade / Slide)の一つを指定することで設定するために使われます。FadeかSlideを指定すると、ステータスバーがページを出入りする際に0.25秒のアニメーションが実行されます。

Delaying Content Touches in a ScrollView

iOSでは、ScrollView内でタッチジェスチャーが開始される時、暗黙のタイマーが呼ばれます。そしてScrollViewは、そのタイマーの間のユーザーのアクションに基づいて、そのジェスチャーを処理するか、その中のコンテンツに伝えるかを決めます。デフォルトではiOSのScrollViewはコンテンツのタッチを遅らせますが、これはScrollViewのコンテンツでジェスチャーが発生すべきときに発生しない、というようないくつかの状況での問題の原因となりえます。したがって、このplatform-specificはScrollViewがタッチジェスチャーを処理するか、その中のコンテンツに伝えるのかどうかを制御します。XamlではScrollView.ShouldDelayContentTouches添付プロパティにbool値を設定することで使用します。

<MasterDetailPage ...
                  xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
    <MasterDetailPage.Master>
        <ContentPage Title="Menu" BackgroundColor="Blue" />
    </MasterDetailPage.Master>
    <MasterDetailPage.Detail>
        <ContentPage>
            <ScrollView x:Name="scrollView" ios:ScrollView.ShouldDelayContentTouches="false">
                <StackLayout Margin="0,20">
                    <Slider />
                    <Button Text="Toggle ScrollView DelayContentTouches" Clicked="OnButtonClicked" />
                </StackLayout>
            </ScrollView>
        </ContentPage>
    </MasterDetailPage.Detail>
</MasterDetailPage>

あるいは、C#からfluent APIを使って使用します。

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

scrollView.On<iOS>().SetShouldDelayContentTouches(false);

ScrollView.On<iOS>メソッドはこのplatform-specificがiOS上でのみ動作することを指定します。ScrollView.SetShouldDelayContentTouchesメソッドは、Xamarin.Forms.PlatformConfiguration.iOSSpecific名前空間に存在し、ScrollViewがタッチジェスチャーを処理するのか、その中のコンテンツに伝えるのかどうかを制御するために使用されます。さらにSetShouldDelayContentTouchesメソッドはコンテンツのタッチを遅らせるかどうかを返すShouldDelayContentTouchesメソッドを呼ぶことでコンテンツのタッチの遅延を切り替えるためにも使用できます。

scrollView.On<iOS>().SetShouldDelayContentTouches(!scrollView.On<iOS>().ShouldDelayContentTouches());

その結果、ScrollViewはコンテンツのタッチを受け取る遅延は無効にできます。そのためこのシナリオでは、MasterDetailPageのDetailではなくSliderがジェスチャーを受け取ります。

(結果は元ページの画像を参照してください)

Summary

この記事では、iOSのXamarin.Forms組み込みのplatform-specificsの使用方法を説明しました。platform-specificsは、effectsやcustom renderersを実装することなく、特定のプラットフォームでだけ利用できる機能の使用を可能にします。

感想

今回は各項目でほとんど同じ言い回しだったので最初の方を一度訳したらあとは結構楽でした。 相変わらずensureは訳しにくいというか、訳すと仰々しくなるのでもう無視してます。自分が英作文する時には絶対に出てこないワードだけどきっと必要なニュアンスが含まれてるんでしょうね。 あとfluent APIとかいう言い方は技術系では一般的なんだろうか。これは使われ方とかから推測するしかなかった。

内容の方は、Platform-Specificで結構いろいろできるようになってるんだなと思いました。というかほとんど知らない内容でした。これを知っていればわざわざEffectとかCustom Rendererとか作る必要無かったという場面がちらほらありそうなので覚えていて損はないかと思いました。

次回予定

developer.xamarin.com

*1:拡張メソッドの戻り値のIPlatformElementConfigurationを利用したメソッドチェーン全体をそう呼んでいるっぽい。