Xamarin.Forms 向けのUIライブラリを提供する人向けの内容です。
XAML Previewer によって、XAML のコーディングも捗るようになってきました。
Custom Renderer を使って、独自のコントロールを作成し、それを Page で使用した場合、XAML Previewer は、そのカスタムコントロールもレンダリングしようとします。
アプリ実行時とほぼ変わらない処理が行われるようです。 その為、特に意識しなくとも、カスタムコントロールをプレビューすることができます。
一方で、プレビュー時には、アプリ実行時とは異なる動きをさせたい場合があります。
私の作成している Xamarin.Forms.GoogleMaps は地図を表示するためのカスタムコントロールです。 これは、次の理由で、プレビュー時には、実行時の処理をさせたくありません。
Xamarin.Forms.GoogleMaps 以外でも、例えば Android/iOS 端末内のデータを読んで表示・描画するようなものや C/C++ のライブラリに依存したカスタムコントロールも該当すると思います。
このような場合、XAML Previewer による プレビュー中かどうか を判断し、プレビュー中なら背景色をグレイにする、何か文字を表示する、などの特別な処理をしたいです。
Windows.Forms で言えば DesignMode
プロパティ、Blend だと DesignModeEnabled
に相当するような、「プレビュー中かどうか」を明確に知る手法は、現在の Xamarin.Forms には提供されていませんでした。
で紹介されていますが、 「Application.Current
が null
だったらプレビュー中である」という判断方法があるようです。
ところが、App.xaml.cs
で MainPage = new NavigationPage(new SomePage());
としている場合、iOS ではプレビュー中にも関わらず Application.Current
が null
ではありませんでした(XAML Previewer が App.xaml.cs
もパースして実行している?)。
で書きましたが、ライブラリを提供する場合、そのアセンブリが確実にロードされるようにするには、MainActivity.cs
や AppDelegate.cs
で、UIライブラリの何らかのメソッド(MyLib.Init()
のような)を明示的に呼び出す必要があります。
これは、「実行時にのみ、 MyLib.Init()
が呼び出される」前提になるので、「MyLib.Init()
が呼び出されていなければプレビュー中である」と疑似的に判断することができます。
こちらは XAML Previewer でも正常に判断されました。
Xamarin.Forms.GoogleMaps では、Xamarin.FormsGoogleMaps.Init()
という初期化メソッドを提供していますが、これが呼び出されていない場合には、地図の描画をせず、背景色付きのラベルを配置するようにしました。
その修正のコミットが↓です。
OnElementChanged
で、Init
が呼び出されていない場合は、MapView
ではなく UILabel
をセットするようにしています。
// iOS/MapRenderer.cs
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
// For XAML Previewer or FormsGoogleMaps.Init not called.
if (!FormsGoogleMaps.IsInitialized)
{
var label = new UILabel()
{
Text = "Xamarin.Forms.GoogleMaps",
BackgroundColor = Color.Teal.ToUIColor(),
TextColor = Color.Black.ToUIColor(),
TextAlignment = UITextAlignment.Center
};
SetNativeControl(label);
return;
}
// 以下略
前述のコミットにも示されていますが、Android/iOS それぞれの Custom Renderer の実装で、
コンストラクタ, OnElementChanged
, OnLayout
, OnElementPropertyChanged
, LayoutSubviews
など、親クラスを override しているメソッドは、プレビュー中にも呼び出される可能性があるので、処理をスキップした方がよいです。
Xamarin.Forms.GoogleMaps では、以下のような感じで処理をスキップしています。
これらを対応した結果、Xamarin.Forms.GoogleMaps は、Visual Studio for Mac の XAML Preview では下図のような背景色付きのラベルで表示されるようになりました。
プロジェクトが使用している Xamarin.Forms の nuget パッケージが古いとプレビューが表示されないようです(この記事投稿時、2.3.0 では「古い」と言われ、最新の 2.3.3 に上げたら表示されるようになりました)。
尚、未検証ですが、Init
が呼ばれたか、という手法なら、XAML Previewer 以外のプレビューソリューション(Gorilla Player とか)でも使用可能と思われます。