Xamarinを使ったウェザタイのマルチプラットフォーム化は順調に進んでいる。ただ、いろんなプラットフォームの仕様やらバグやらを回避するのが大変。ネット情報も少ないので、1個解決するのに1日かかるとかざら。オープンソースになってるのがせめてもの救い。Xamarin.Forms自体はかなりいいので、変な動作が多いのはもったいない。世の中に広めるためにも、今回分かったTipsをここに書いておくことにする。決して愚痴ではない。
Xamarin Forms for UWP
- 凝ったUIをリストにしてで表示する場合、Xamarin.Forms的にはListViewのTemplateSelectorを使うのがお勧めのようだが、やってみるとテキストボックス(Entry)のカーソルが表示されなかったりPickerの選択肢が出なかったり(だったかな?)いろいろなことが起こる。結局ScrollView+StackLayoutに落ち着いた。
- で、ScrollView+StackLayoutにすると、どこをクリックしても最初のテキストボックスがフォーカスされてしまう。ソースを見るとそういう仕様っぽいけど、困るので、ネット情報を参考に、ScrollViewの最初のアイテムとしてサイズ0のButtonを置くことで回避した。
- XAMLで画像を表示するとき、Anrdoidなどでは画像をResources/Drawableに置けばルートからのパスで指定できるが、同じパスでUWPで使えるようにするには・・・ってことでUWPではルートに画像を置けば読み込めた。気持ち悪いけど。
- ファイルの扱いも結構困る。Android等ではセキュリティ的に問題なければ自由にファイルパスを指定して扱えるが、UWPはFilePickerなどで指定したファイルか、プロファイル領域しか使えないし、Storageクラスを介さなければならないので自由度が低い。私はファイル操作をラップするクラスを作ってどのプラットフォームでも統一的に扱えるようにしている。
Xamarin Forms for Android
- ScrollViewと他のUI部品を上下に配置すると、ScrollViewが他の部品をはみ出して画面一杯に表示されてしまう。ScrollViewのIsClippedToBoundsにTrueを設定すればOK。
- デフォルトではスプラッシュ画面がなく、真っ白な画面が表示される。公式ドキュメントの通りにThemaを作って解決。
Xamarin Forms for Mac
- ContentPageのBackgroundImageで背景画像を出していたのだが、Mac版だけはタイル表示になってしまう。しょうがないのでContentPageに画面全体のGridを用意してAspect FillにしたImageを配置した。
- NavigationViewのPopAsyncを何回か実行して一気にタイトル画面に戻るとかしていると、Macだけは途中の画面が表示されてしまう。これはPopAsyncのAnimationパラメータをfalseにすればよい。
- ListViewの背景がどうやっても白くなってしまうのに悩まされる。ListViewのBackgroundColorにTransparentを設定するだけだとダメで、さらに後ろに白い背景があるっぽい。ソースを見たらあえて白くしているようだったので、ListViewRendererを作って、NativeTableView.EnclosingScrollView.DrawsBackgroundをfalseにする。さらに、これだけだとScrollViewをドラッグしたときに後ろに白い線が見えることがあるのでNativeTableView.HeaderViewをnullにしてようやく完全に透明になった。
Xamarin Forms for iOS
- ListViewに罫線が入ってしまう。ListViewのSeparatorVisibilityをNoneにすることで消せる。
- DLLは使えず全部StaticLinkになるのでネイティブP/Invokeしている場合はスタティックリンクにする必要がある。また、他のプロジェクトのクラスの型を参照する場合、GetTypeにモジュール名は付けない。
- 何故か分からないけどPCLの中にあるクラスに対してGetTypeはできないっぽい。入力方式プラグインはPCLじゃなくて普通のライブラリにした。
- iOSネイティブのときは、UIInputTextを実装したUIViewでInputDelegateで受け取ったパラメータがUIKeyboardImplで、そのままUIInputTextDelegateにキャストできた。それを使ってTextWillChangeとかTextDidChangeを呼び出し、内部テキストを変更したことをシステムに通知できた。でも、XamarinだとWeakInputDelegateのパラメータをUIInputTextDelegateにキャストできない。ヘルプにはWeakだと実際の継承関係以外の使い方ができるように書いてある気がするけど、どうやるのが正解なんだろう。とりあえず今回はSimpleInputTextのサンプルのように[Adopts (“UITextInput”)]で実装した。ただ、それだとIUITextInputインターフェースを実装しないので、結局TextWillChangeとTextDidChangeを呼び出すパラメータに何を使えば良いのか分からなくなる。なので、わざわざIUITextInputを実装したラッパーを作って[Adopts (“UITextInput”)]を実装したクラスを呼び出すようにして、ようやくiOSネイティブ版と同じ動作になった。