Xamarin.Forms for Unityの概要の追記

前回記事の後、実装の見直しをしたのでちょっと状況が変わりました。

tan-y.hatenablog.com

Xamarin.Forms の VisualElementRenderer は標準的な手続きに従う場合、デフォルトコンストラクタでインスタンス生成ができるようにし、ExportRendererAttribute で VisualElement と VisualElementRenderer の関連付けを定義する事になっているようですが、これに従うことができないので今のところは UnityFormsApplicationActivity というクラスに集約しています。

と書きました。
これの原因は Xamarin.Forms.Internals.Registrar クラスの GetHandler メソッド

object handler = Activator.CreateInstance(handlerType);

のためだったのですが、よくよく考えたら VisualElementRenderer を MonoBehaviour 継承にしなければいいんじゃね?てことでほぼ通常の Platform 実装の構造にすることができました。現状では通常の Platform 実装と同じように ExportRendererAttribute で関連付けを指定できますので Custom Renderer もいけるはず。

ExportRendererAttribute はアセンブリ属性として定義しますが、 WebGL ビルド (IL2CPP) が実はアセンブリ属性をサポートしてないかとちよっと疑いましたが、特に問題なく動作しました。 XAML Loader が WebGL で動作しないのはこの辺かなあと思ったのですが。

VisualElementRenderer の実装クラスでは UI を描画するためのリソースを生成する処理の実装が必要になります (CreateBaseComponent をオーバーライド) 。標準の実装では予め対応を定義づけておいた Prefab からインスタンス生成します。

単純にコンストラクタで処理が記述できないのは

  • VisualElementRenderer が Unity 的には画面 (Scene) 上で管理する "GameObject" に適用する MonoBehaviour (直接的には MonoBehaviour ではなくなりましたが論理的には) であること。
  • MonoBehaviour は本体である GameObject が存在しないとインスタンス生成すらできないこと (GameObject.AddComponent メソッドを参照)
  • MonoBehaviour, GameObject は Unity.Object 継承であり、直接 new でインスタンス化できないこと

あたりが理由です。 Unity だけやってる時は「そういうものだ」で受け入れてしまってますがこういう時面倒になってきます。

描画リソース (コンポーネント) 生成に Prefab を利用しているのは、コードで生成処理を記述するのが実質不可能なための苦肉の策だったのですが、 Prefab を利用することで Custom Renderer がなくなても独自にデザインした UI コンポーネントをテンプレート的に設定できるので、このやり方は結果的によかったかなあと思います。

次の課題

NavigationPage の対応かなーというのはあるのですが、実は下記二つをどうやって対応するか悩み中。

  • ImageView
  • Opacity

「え、 Unity だから簡単じゃないの?」と思うでしょう。
Unity だからこそ逆に面倒なんですよ・・・