Taoffi's blog

prisonniers du temps

Xamarin forms: a small step for mankind!

My friends at UXDivers are doing a great job in bringing Xamarin Forms into the developer's desktop with nicely crafted design and some extra facilities like their Gorilla player which allows you to instantly view your xaml output at design-time.

UXDivers' Grial U.KIT also exposes a wide range of controls and design ideas that enriches applications with ready-made and adaptable Xamarin Forms elements.

Handling fonts with Xamarin Forms

One of the interesting features of Grial is using awesome web font to create attractive buttons design with a minimal resource cost.

As fonts seem to be one interesting resource for applications and, in the same time, are handled differently in target platforms (Android, iOS and Win Phone), I did a small dive into the subject.

My conclusions so far are quite simple:

  • To use a font, in Xamarin Forms solution, you should first get its definition file (preferably a .ttf)
  • According to the platform specific project, you should place that file:
    • For Android project: in the Assets folder. Build action = AndroidAsset (no copy)
    • For iOS project: in the Resources folder. Build action = Bundled resource (no copy). The name of the font file should also be included in the application's info.plist file. Example:

      <key>UIAppFonts</key>
          <array>
              <string>Novecentowide-Bold.ttf</string>
          </array>
       

    • For Window Phone project: in the Assets folder (or sub folder of it). Build action = Content (no copy)
  • For Android: you need a custom renderer in order to apply the selected font
  • For iOS and WP: the font family name is all what you need to apply the font

 

Styles and Font family naming

As font family naming conventions vary for each platform, the ideal way is to use the Xamarin Forms OnPlatform to define this.

In this example we create an on platform string resource (in App.xaml) with the key "fontNovecentoName":

 

<OnPlatform x:TypeArguments="x:String"
    Android="Novecentowide-Bold.otf"
    iOS="Novecentowide-Bold"
    WinPhone="./Assets/Fonts/Novecentowide-Bold.otf#Novecento"
    x:Key="fontNovecentoName"/>

 We can then refer to this font family name in a Label style, like in the following:

 

<Style TargetType="Label" x:Key="labelNovecento">
    <Setter Property="FontFamily"    Value="{StaticResource fontNovecentoName}" />
    <Setter Property="FontSize"        Value="16" />
</Style>

 

Once we defined this style as an application resource, we can use it anywhere in our xaml views to create labels using the font:

<Label Style="{StaticResource labelNovecento}" Text="This should show Novencento font" />

 

That label will directly show on iOS and Windows Phone with no extra work.

For Android, we should use a 'Custom renderer' (deriving from Xamarin.Forms LabelRenderer) whose role is to extract the font family name from the xaml code and try to apply it to the target label.

 

Android custom renderer

'Custom renderers' is a vast subject. To summarize: the role of a custom renderer is to do the job of translating xaml instructions into on-screen graphical items according to each platform constraints. There is a Xamarin built-in renderer for each type of Xamarin Forms controls (Views). If you need an extra rendering job for a control, you create your own renderer inheriting the built-in one for the control… and you override one or more of that built-in renderer's methods to add your specific functionality.

 

For our subject, we need to create a custom Label renderer in Android to apply the desired font if any is specified.

Sample code:

 

 
// we should export our renderer in order to be called
[assembly: ExportRenderer (typeof (Label), typeof (iFontLabelRenderer_Android))]

namespace iFonts.Droid
{
   public class iFontLabelRenderer_Android : LabelRenderer
   {
     // override the base’s OnElementChanged
     protected override void OnElementChanged (ElementChangedEventArgs<Label> e)
     {
        base.OnElementChanged (e);

        var label      = Control as TextView;
        var  xfControl  = Element as Label;

        // try to find the font family name
        string     fontName= xfControl == null ? null : xfControl.FontFamily;

        if(string.IsNullOrEmpty(fontName))
           return;

        try
        {
           // try to create and apply the font
           Typeface font = Typeface.CreateFromAsset (Forms.Context.Assets, fontName);
           label.Typeface = font;
        }
        catch (Exception)
        {
           // throw exception if you find this useful
           //throw;
        }
     }
   }
}
 

 

 

 

 

 

 

Download the sample app. iFonts.zip (944.41 kb)