- 今回作るもの
- やりかた
- つらかったところ
- 参考記事
今回作るもの
アイコンがボタンになっているやつを作成します。 画像でボタンを作る場合と比べて、ベクタイメージなので、様々な解像度に対応できる利点があります。 まぁ、以下の画像を見ていただくのが速そうなので。。。
iOS
Android
UWP アプリ
外部フォントとは
iOS, Android, UWP で内蔵されているフォントの種類が違うので、今回は、外部にあるフォントを埋め込んでそれを使うことで、どのプラットフォームでもおなじフォントがつかえるようにします。
今回は、 Windows10 に標準搭載されている Segoe MDL2 Assets を使用していきます。コピーしてどこかに置いておくと扱いやすいかもしれないです。
やりかた
カスタムレンダラー
Xamarin.Forms から各プラットフォーム固有の機能をつかっていかなければいけないので、 カスタムレンダラー ってのを使っていきます。
カスタムレンダラーについては、以下のサイトが詳しいかなと
Xamarin.Forms プロジェクトでレンダラー用のクラスを作成
まずは、 Xamarin.Forms のプロジェクトで カスタムレンダラーの元となるクラスを作成していきます。
イベントとか、プロパティには特に手を加えないので、こっちは基本シンプルな感じです。
ポイントとしては、 ボタンにカスタムを加えるので、 Button クラスを継承しているところぐらいでしょうか。
自分の場合は、以下のようなクラスになりました。
CustonFontTextView.cs
using Xamarin.Forms; namespace LTTimer.View { public class CustonFontTextView : Button { } }
Xamarin.UWP プロジェクトでレンダラー用クラスを作成
次に、 UWP アプリで実装をしていきます。
View/ 配下にコードを置きました。 また、フォントファイルを Assets/Fonts/ 配下に置きました。
ビルドアクション
- コンテンツ
出力ディレクトリにコピー
- コピーしない
CustonFontTextViewRenderer.cs
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; using LTTimer.UWP.View; using Xamarin.Forms.Platform.UWP; // おまじない // 第一引数に、Xamarin.Forms プロジェクト内においてあるカスタムレンダラー元のクラスを指定 // 第二引数に、Xamarin.UWP プロジェクト内においてあるカスタムレンダラー先のクラスを指定 [assembly: ExportRenderer(typeof(Xamarin.Forms.Button),typeof(CustonFontTextViewRenderer))] namespace LTTimer.UWP.View { // カスタムレンダラー元が Button クラスを継承したものなので、 ButtonRenderer を継承する public class CustonFontTextViewRenderer: ButtonRenderer { // ネイティブビューを作成してにゃーんする protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e) { base.OnElementChanged(e); // Button のところに設定された FontFamily を取得して、どのフォントを使うのか選択するのに使う // もし、設定してなかったら NullReferenceException がでちゃうから、 Null チェックしつつ取得してく var fontfamily = e.NewElement?.FontFamily; // 取得できてなかった時のために if (fontfamily != null) { var element = (Button) Control; // UWP は比較的簡単にかける element.FontFamily = new FontFamily(e.NewElement.FontFamily); } } } }
Xamarin.Android プロジェクト で レンダラー用のクラスを作成
コードは View フォルダに配置しました。 Android はフォントファイルを Resource/Fonts に置く
ビルドアクション
- AndroidAsset
出力ディレクトリにコピー
- コピーしない
CustonFontTextViewRenderer.cs
using Android.Graphics; using Android.Widget; using LTTimer.Droid.View; using Xamarin.Forms; using Xamarin.Forms.Platform.Android; using Button = Xamarin.Forms.Button; // おまじない // 第一引数に、Xamarin.Forms プロジェクト内においてあるカスタムレンダラー元のクラスを指定 // 第二引数に、Xamarin.UWP プロジェクト内においてあるカスタムレンダラー先のクラスを指定 [assembly:ExportRenderer(typeof(Button),typeof(CustonFontTextViewRenderer))] namespace LTTimer.Droid.View { // カスタムレンダラー元が Button クラスを継承したものなので、 ButtonRenderer を継承する public class CustonFontTextViewRenderer: ButtonRenderer { protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e) { base.OnElementChanged(e); // Button のところに設定された FontFamily を取得して、どのフォントを使うのか選択するのに使う // もし、設定してなかったら NullReferenceException がでちゃうから、 Null チェックしつつ取得してく var fontFamily = e.NewElement?.FontFamily?.ToLower(); if (fontFamily != null) { var label = (TextView)Control; // Android でLabelのフォントファミリーを設定するには、 Typeface.CreateFromAsset メソッドを使う // フォントサイズは特に変えたくなかったので、第二引数にもともとのフォントサイズを代入しています。 label.Typeface = Typeface.CreateFromAsset(Context.Assets,e.NewElement.FontFamily); } } } }
## Xamarin.iOS プロジェクト で レンダラー用のクラスを作成
ios は、 フォントファイルの埋め込みが少し面倒でしたにゃーんした
今回も、 View 配下にコードを配置しました。
CustonFontTextViewRenderer.cs
using LTTimer.iOS.View; using UIKit; using Xamarin.Forms; using Xamarin.Forms.Platform.iOS; // おまじない // 第一引数に、Xamarin.Forms プロジェクト内においてあるカスタムレンダラー元のクラスを指定 // 第二引数に、Xamarin.UWP プロジェクト内においてあるカスタムレンダラー先のクラスを指定 [assembly:ExportRenderer(typeof(Button),typeof(CustonFontTextViewRenderer))] namespace LTTimer.iOS.View { // カスタムレンダラー元が Button クラスを継承したものなので、 ButtonRenderer を継承する public class CustonFontTextViewRenderer: ButtonRenderer { protected override void OnElementChanged(ElementChangedEventArgs<Button> e) { base.OnElementChanged(e); // Button のところに設定された FontFamily を取得して、どのフォントを使うのか選択するのに使う // もし、設定してなかったら NullReferenceException がでちゃうから、 Null チェックしつつ取得してく var fontFamily = e.NewElement?.FontFamily; if (fontFamily != null) { var element = Control; // UIFont のスタティックメソッドである、 **FromName()** を使い作成したインスタンスを 設定していく element.TitleLabel.Font = UIFont.FromName(fontFamily,element.TitleLabel.Font.PointSize); } } } }
iOS のフォントの設定はいろいろ大変
iOS のフォントの設定等はいろいろ大変だったので別セクションにします。
いつもどうり、Xamarin.iOS のプロジェクトにフォントを追加
iOS でも、ほかのプラットフォームと同じように、 Resource/Fonts/ 配下に配置します。
ビルドアクション
- AndroidAsset
出力ディレクトリにコピー
- コピーしない
info.pilot へ設定の追加
Xamarin.iOS のプロジェクトにある、 info.pilot ファイルを開きます。
画面の左下にある以下のようなボタンをクリックします。
テキストボックス的なのがでてくるので、 Font Provided by application と入力します。途中で入力補完がかかるので、 それを選択します。
次に、 String と書かれた部分の右側をダブルクリックして、文字を編集できるようにします。
そこへ、 Fonts/{FontFileName} と入力します。
完成したので アプリに表示させてみる
MainPage.Xaml を開き、追記して表示していきます。 ポイントは、 OnPlatform を使い、iOS,Android,UWP で処理を切り分けているところでしょうか。
Font-Family で設定する値
iOS
フォント名、 Mac の FontBook でフォントを開いたときに、 PostScript名 というところの名前を入力します。
Android
Resource フォルダを起点として、フォントファイルまでのパスを記入します。
UWP アプリ
今回使ったのは、 Windows 10 なら標準に入っているということで、 フォント名だけを入れるだけでおkです。
MainPage.xaml
<view:CustonFontTextView Text=""> <view:CustonFontTextView.FontFamily> <OnPlatform x:TypeArguments="x:String" iOS="Segoe MDL2 Assets" Android="Fonts/SEGMDL2.TTF" WinPhone="Segoe MDL2 Assets"> </OnPlatform> </view:CustonFontTextView.FontFamily> </view:CustonFontTextView>
動かしてみた
iOS
Android
UWP アプリ
つらかったところ
フォントを設定しても表示されない
iOS で Info.Pilot へ設定を追加しないといけないところに気づけなくて、ハマった
パスをチェック
タイポしてると フォントファイルを取得できずに NullReferenceException が発生してアプリが落ちることがたまによくあった
再起動すればOK
最後に悩んだら、再起動すればなんとかなった。
参考記事
https://docs.microsoft.com/ja-jp/windows/uwp/style/segoe-ui-symbol-font#a-namelayering-and-mirroringa重ね合わせとミラーリングdocs.microsoft.com