Taoffi's blog

prisonniers du temps

Xamarin forms fonts: Handling droid formatted text spans

As we have seen in a previous post, it is relatively easy to handle custom fonts using Xamarin forms. The only tedious platform in this domain is Android where you need to write a custom renderer.

In the first version of Droid custom renderer, I didn't handle the Labels Formatted Text.

Formatted texts can be used like in this sample:

 

<Label>
    <Label.FormattedText>
        <FormattedString>
            <FormattedString.Spans>
                <Span
                    Text="Allura span"
                    ForegroundColor="Lime"
                    FontSize="36"
                    FontFamily="{StaticResource fontAlluraName}"
                    />
                <Span
                    Text=" "
                    FontSize="{StaticResource awesomeSize}"
                    ForegroundColor="Lime"
                    FontFamily="{StaticResource fontawsomeName}"
                   />
           </FormattedString.Spans>
        </FormattedString>
    </Label.FormattedText>
</Label>



 

That is a Droid-only problem!

In Windows Phone and iOS, once the fonts have been included in the project, you have nothing to do. The problem is with the Droid custom renderer!

Android has a font Typeface which acts on the Label globally, and another Type 'TypefaceSpan' which acts on a region (span) of the label's formatted text.

In the first version of Droid renderer sample, we have set the font TypeFace for the label. If that label contained formatted text with spans, they were simply ignored (rendered with a default system font).

 

TypefaceSpan (namespace Android.Text.Style in Mono.Android.dll) is a class derived from à CharacterStyle whose role is to draw a span's text with the specified font family name.

 

A solution

After searching the Internet for a while, the question didn't seem to have many people talking about.

Luckily, I fall on a piece of code (a secretJ) where I found a link about an awesome solution proposed in this page.

In fact, you may derive a class based on TypefaceSpan, and override its methods according to your specific information (notably the span's font and its attributes).

 

A Label object has a FormattedText member which may contain one or more text Spans. Each span has a set of properties of which you find the font family (and font attributes) to be applied to the span's text.

So that now becomes manageable: your derived CustomTypefaceSpan can then create the font and draws the span's text accordingly.

 

 

 

The updated version of the sample code contains more details. Have fun doing more additions… would be nice to keep me posted!

 

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)