読者です 読者をやめる 読者になる 読者になる

yamamoWorks

.NET技術を中心に気まぐれに更新していきます

Xamarin Formsでアイコンフォントを表示する

UWPではアイコンフォントがSymbol 列挙値として定義されていて簡単にアイコンフォントを表示する事ができますが、残念ながらXamarinにはこのような機能はありません。 f:id:yamamoWorks:20160702164355p:plain:w400

そこでXamarin Formsでも同じアイコンフォントを使えるようにしたいと思います。

準備

Symbol 列挙値で表示されるのはSegoe MDL2 Assetsというフォントで、Windows 10から組み込まれています。 UWPアプリの開発でハンバーガーメニューを表示する際などにもSymbolThemeFontFamilyとして用いられます。 f:id:yamamoWorks:20160702165747p:plain:w400

エクスプローラーで「C:\Windows\Fonts」を開き、フォントファイルを取り出します。他のフォルダにコピーすると分かりますがファイル名は「segmdl2.ttf」です。 f:id:yamamoWorks:20160702221833p:plain:w400


[追記]
Segoe MDL2 Assetsフォントのライセンスについて記載されたドキュメントが見つからない為、ソフトウェアに組み込んで配布可能であるか不明です。このブログ記事ではこれを許可や推奨するものではありません。


Font Awesome フォント

さて、UWPのアイコンフォントをiOSとAndroidでも表示したいというのが発端でしたが、せっかくなので他のアイコンフォントも表示してみます。 今回は「Font Awesome」のアイコンフォントを使います。ダウンロードかGitHubから「FontAwesome.otf」を入手します。

fontawesome.io

フォントの登録

UWP

「FontAwesome.otf」をUWPプロジェクトのどこかに格納しプロパティを以下に設定します。 今回はAssets配下に「Fonts」フォルダを作成して格納します。
 Assets/Fonts/FontAwesome.otf

 ビルドアクション : コンテンツ
 出力ディレクトリにコピー : コピーしない

Android

「segmdl2.ttf」と「FontAwesome.otf」をAndroidプロジェクトの「Assets」に格納しプロパティを以下に設定します。 今回は「Fonts」フォルダを作成して格納します。
 Assets/Fonts/FontAwesome.otf
 Assets/Fonts/segmdl2.ttf

 ビルドアクション : AndroidAsset
 出力ディレクトリにコピー : コピーしない

iOS

「segmdl2.ttf」と「FontAwesome.otf」をiOSプロジェクトの「Resources」に格納しプロパティを以下に設定します。 今回は「Fonts」フォルダを作成して格納します。
 Resources/Fonts/FontAwesome.otf
 Resources/Fonts/segmdl2.ttf

 ビルドアクション : BundleResource
 出力ディレクトリにコピー : コピーしない

次に「Info.plist」にフォント情報を追記します。「Info.plist」を右クリックし「ファイルを開くアプリケーションを選択」から「XMLテキストエディタ」を選択します。
「UIAppFonts」キーを作成してフォントファイルのパスをString配列で記載します。
※Resourcesフォルダからの相対パスです

<plist version="1.0">
  <dict>
    <key>UIAppFonts</key>
    <array>
      <string>Fonts/FontAwesome.otf</string>
      <string>Fonts/segmdl2.ttf</string>
    </array>
       :

※ダブルクリックで開くとPlistEditorが表示されますが、それだとフォント情報の登録ができません。

カスタムレンダラーの作成

AndroidではLabel.FontFamily等でフォント名を指定しても独自に追加したフォントは探してくれません。そこでカスタムレンダラーを作る必要があります。

[assembly: ExportRenderer(typeof(Label), typeof(XFApp1.Droid.CustomFontLabelRenderer))]

namespace XFApp1.Droid
{
    public class CustomFontLabelRenderer : LabelRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);

            var fontFamily = e.NewElement.FontFamily?.ToLower();
            if (fontFamily != null && (fontFamily.EndsWith(".otf") || fontFamily.EndsWith(".ttf")))
            {
                var lable = (TextView)Control;
                lable.Typeface = Typeface.CreateFromAsset(Forms.Context.Assets, e.NewElement.FontFamily);
            }
        }
    }
}

既存のフォントの指定と追加したフォントの指定とを区別する為、後者はファイル名で指定する仕様としました。

XAMLの記述

LabelのFontFamilyを以下のルールで記載します。

iOS
 既存のフォント : フォント名
 追加したフォント : フォント名

Android
 既存のフォント : フォント名
 追加したフォント : フォントファイルのパス
 ※Assetsフォルダからの相対パス

UWP
 既存のフォント : フォント名
 追加したフォント : フォントファイルのパス#フォント名
 ※プロジェクトフォルダからの相対パス

    <Label Text="FontAwesome" />
    <Label Text="&#xF099; &#xf230; &#xf09b; &#xf179; &#xf17b; &#xf17a;" FontSize="24">
      <Label.FontFamily>
        <OnPlatform x:TypeArguments="x:String"
                    iOS="FontAwesome"
                    Android="Fonts/FontAwesome.otf"
                    WinPhone="Assets/Fonts/FontAwesome.otf#FontAwesome">
        </OnPlatform>
      </Label.FontFamily>
    </Label>

    <Label Text="Segoe MDL2 Assets" />
    <Label Text="&#xE8FA; &#xE8E1; &#xE74E; &#xE907; &#xE909; &#xE8A3;" FontSize="24">
      <Label.FontFamily>
        <OnPlatform x:TypeArguments="x:String"
                    iOS="Segoe MDL2 Assets"
                    Android="Fonts/segmdl2.ttf"
                    WinPhone="Segoe MDL2 Assets">
        </OnPlatform>
      </Label.FontFamily>
    </Label>

※アイコンに対応する文字コードは下記を参照
Font Awesome Cheatsheet
Segoe MDL2 アイコンのガイドライン

これで各プラットフォームでアイコンフォントが表示できるようになりました。 f:id:yamamoWorks:20160702234900p:plain