C#
iOS
Xamarin

Xamarin.Forms の Label から iOS の UILabel を取り出す

More than 1 year has passed since last update.

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 を修正。


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 を作成。


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 でフックでき、ControlUILabel は取り出せるので、あとはご自由に、という感じ。

この実装だと、すべての Label に Ajusts が適用されてしまう。個別に行いたい場合は、Forms側に Labelから派生した AjustableLabel を作成して使い、ExportRenderer(typeof(Label),… のところを ExportRenderer(typeof(AjustableLabel),… にすればいけるはず。そしてこの方法はカスタムビューを作る手順に通じる(というかそのもの?)はず。

ちなみにこの OnElementChanged は、Nuget の Xamarin.Formsパッケージの Ver1.1.0.6201から利用できる。


実行する

こんな感じで、ちゃんと文字サイズが縮小されました。

Android の方も同じ要領でいけるは…ず。