ぴーさんログ

だいたいXamarin.Formsのブログ

【Xamarin.Forms 2.3.3】 Platform Specifics

Xamarin.Forms 2.3.3で Platform Specifics という機能が追加されました。

これはPCLなどの共通コードからプラットフォーム固有の機能を呼び出したりする類のものです。(ただしコードビハインド限定)

Forumでの紹介文によると...

Introducing Platform Specifics! Features or behaviors that apply to one platform only can now be implemented without requiring custom renderers. These new features/behaviors can then be accessed easily via a fluent code API or XAML.

Vendors can easily add their own Platform Specifics by attaching Effects to them (see 63a924d and 1f9482e for complete example).

This feature implements the framework that enables the new API and also includes several examples of platform specific features, which can be previewed using the Platform Specifics gallery page:

  • Blur support for any VisualElement on iOS
  • Translucent navigation bar on iOS
  • Partially collapsed navigation bar (with icons!) on MasterDetailPage on Windows
  • Toolbar placement options on Windows
  • AdjustResize/AdjustPan on Android (known issue: AdjustResize disables status bar color)

とのこと。

Custom RendererやEffectsを使ってやるようなことが簡単にできる風に書かれていますね。

サンプル

さっぱり分からないと思うのでサンプルコードを用意しました。

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

namespace PratformSpecificsSample
{
    public class MyNaviPage : Xamarin.Forms.NavigationPage
    {
        public MyNaviPage()
        {
            BackgroundColor = Color.Pink;

            var button = new Button
            {
                Text = "Toggle Translucent",
                BackgroundColor = Color.Silver,
            };

            button.Clicked += (sender, args) => On<iOS>()
                .SetIsNavigationBarTranslucent(!On<iOS>().IsNavigationBarTranslucent());

            var content = new ContentPage
            {
                Title = "iOS Translucent Navigation Bar",
                Content = new StackLayout
                {
                    VerticalOptions = LayoutOptions.Center,
                    HorizontalOptions = LayoutOptions.Center,
                    Children = { button },
                }
            };

            PushAsync(content);
        }
    }
}

このコードを実行するとこんな感じになります。

f:id:ticktack623:20170113004240g:plain

ボタンをタップする度に、ナビゲーションバーの透過を切り替えるというiOS固有の効果が発動しています。

Platform Specifics が使われているのはこの部分、

button.Clicked += (sender, args) => On<iOS>()
    .SetIsNavigationBarTranslucent(!On<iOS>().IsNavigationBarTranslucent());

やっていることは On<iOS>().SetIsNavigationBarTranslucent() が透過ON/OFFのセット、 On<iOS>().IsNavigationBarTranslucent() が現在の透過状態の取得ですね。

Element.On<T>() を入り口として、「対象Elementとプラットフォームの組み合わせという文脈に固有な機能をPCLから呼び出せる」というのが Platform Specifics の意義といえるでしょう。

BoxViewの例

例えば、BoxViewに続けて .On<iOS>(). と入力するとインテリセンスから GetBlurEffect()UseBlurEffect() が呼び出せて...

f:id:ticktack623:20170113004413j:plain

.On<Android>(). には呼び出せるものが無い、といった塩梅です。

f:id:ticktack623:20170113004436j:plain

使い方まとめ

1. usingを追加

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;

2. だいたいクラス名衝突が発生するので修正する

これはPlatform Specificsの実装が悪い。

なぜNavigationPageに対する拡張メソッドを定義するクラスを「NavigationPage」にしてしまうのか……

3. Element(ApplicationとかPageとかViewのこと)の .On<TIConfigPlatform>() を呼ぶ

Xamarin.Forms 2.3.3時点でTIConfigPlatformに入れられるのは以下の3種類。(GitHubのコード上ではTizenも追加されているので2.3.4には入ってくるかも)

public sealed class Android : IConfigPlatform { }
public sealed class iOS : IConfigPlatform { }
public sealed class Windows : IConfigPlatform { }

4. インテリセンスで使いたい機能を選ぶ

TElement.On<TIConfigPlatform>() の戻り値は IPlatformElementConfiguration<TIConfigPlatform, TElement> のインスタンスとなっており、プラットフォーム固有機能は拡張メソッドで実装されています。つまり後付けなので自分で実装するのもアリ。

ライブラリ開発者向け情報

Xamarin.Formsのカスタムコントロールなどを配布する場合、IElementConfiguration<TElement>を実装してPlatform Specificsのエントリポイント用意してあげるといいかもしれない。

(プラットフォーム固有機能は拡張メソッドで生やせるけども、エントリポイントはコントロールで実装しなければならないため)