Xamarin.Forms でどうにかしたい iOS と Android の違い の「文字の自動縮小」の自己回答。
Xamarin.Forms で定義した Label
は、iOS では UILabel
となるはずなので、その過程のどこかでフックできれば UILabel.AdjustsFontSizeToFitWidth
が仕込める、と目論んで、ホントにできたのでメモ。
要点
Forms→ネイティブのフックは PageRenderer でできる。その中で得られる UIView(のサブクラス)は、Label と UILabel の両方の参照を持っているので、あとは使うだけ。
ページでなく、UIパーツレベルでフックできたので、全面的に書き換えた。
やってみる
参考にしたのは https://github.com/xamarin/xamarin-forms-samples/tree/master/Forms2Native 。
このサンプルをちょっと改造して試した。
まずは Forms側の MySecondPage.cs を修正。
public class MySecondPage : ContentPage
{
public Label MyLabel { get; private set; }
public MySecondPage ()
{
this.MyLabel = new Label
{
Text = "Too loooooooooooooooooooooooong label",
Font = Font.SystemFontOfSize(30d),
LineBreakMode = LineBreakMode.NoWrap
};
Content = new StackLayout
{
Orientation = StackOrientation.Vertical,
VerticalOptions = LayoutOptions.CenterAndExpand,
Children =
{
this.MyLabel
}
};
}
}
ラベルを配置。とても文字が長いので全部は表示しきれない。
次に iOS側に MyLabelRenderer.cs を作成。
using System;
using Xamarin.Forms;
using Forms2Native;
using Xamarin.Forms.Platform.iOS;
using MonoTouch.UIKit;
[assembly:ExportRenderer(typeof(Label), typeof(MyLabelRenderer))]
namespace Forms2Native
{
public class MyLabelRenderer : LabelRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
this.Control.AdjustsFontSizeToFitWidth = true;
}
}
}
ExportRenderer
で「FormsのLabel
は、MyLabelRenderer
を使う」と定義している。
するとすべての Label
の生成時を OnElementChanged
でフックでき、Control
で UILabel
は取り出せるので、あとはご自由に、という感じ。
この実装だと、すべての Label に Ajusts が適用されてしまう。個別に行いたい場合は、Forms側に Labelから派生した AjustableLabel
を作成して使い、ExportRenderer(typeof(Label),…
のところを ExportRenderer(typeof(AjustableLabel),…
にすればいけるはず。そしてこの方法はカスタムビューを作る手順に通じる(というかそのもの?)はず。
ちなみにこの OnElementChanged
は、Nuget の Xamarin.Formsパッケージの Ver1.1.0.6201から利用できる。
実行する
こんな感じで、ちゃんと文字サイズが縮小されました。
Android の方も同じ要領でいけるは…ず。