Recently I had a requirement to use custom fonts (a font other than one present in a device) in one of my Xamarin forms apps, so I looked for the same in Xamarin documentation and found that the example is using Custom render to implement the same in Android apps. This would have been fine before Xamarin Forms 2.3 was released, but now we have an awesome feature called Effects to implement these kind of small platform specific customizations, so that we don’t need to create a new custom control for every small platform specific change needed in the control. This article will show how to implement custom fonts in Android iOS & UWP apps using effects.
So first create a new project in Xamarin/Visual Studio then perform the changes/additions mentioned in following sections.
Changes in PCL project
- Create a new class file named ‘CustomFontEffect’ and add the following code to it,
- public static class CustomFontEffect
- {
- public static readonly BindableProperty FontFileNameProperty = BindableProperty.CreateAttached("FontFileName", typeof(string), typeof(CustomFontEffect), "", propertyChanged: OnFileNameChanged);
- public static string GetFontFileName(BindableObject view) {
- return (string) view.GetValue(FontFileNameProperty);
- }
- public static void SetFontFileName(BindableObject view, string value) {
- view.SetValue(FontFileNameProperty, value);
- }
- static void OnFileNameChanged(BindableObject bindable, object oldValue, object newValue) {
- var view = bindable as View;
- if (view == null) {
- return;
- }
- view.Effects.Add(new FontEffect());
- }
- class FontEffect: RoutingEffect {
- public FontEffect(): base("Xamarin.FontEffect") {}
- }
- }
- In the above mentioned code we are creating a custom effect where we are creating a new property named ‘FontFileName’ for the Bindable object to which the effect will be attached. The implementation of this effect will have to be written in Platform specific projects.
- In order to implement custom fonts using XAML, set the ‘FontFamily’ of label per the following XAML code,
- <Label Text="This custom font 'AbeatByKai' (First in selection picker) is Set in XAML as an Example, This will not change. " local:CustomFontEffect.FontFileName="abeatbyKaiRegular">
- <Label.FontFamily>
- <OnPlatform x:TypeArguments="x:String">
- <OnPlatform.iOS>AbeatByKai</OnPlatform.iOS>
- <OnPlatform.Android></OnPlatform.Android>
- <OnPlatform.WinPhone>/Assets/Fonts/abeatbyKaiRegular.ttf#AbeatByKai</OnPlatform.WinPhone>
- </OnPlatform>
- </Label.FontFamily>
- </Label>
- No font name is provided for Android platforms as it requires the name of the font file without extension to create the font in platform specific code, that name we are passing in the new property ‘FontFileName’ which is attached while attaching the effect to the control (codelocal:CustomFontEffect.FontFileName=”abeatbyKaiRegular” ).
The font name to be used in iOS & UWP/WinPhone (after #) can be taken out from the font file by opening it in font installer as highlighted in following screenshot.
- In order to implement custom fonts in code behind use the following C# code,
- Device.OnPlatform(iOS: () =>
- {
- lblSample.FontFamily = "AbeatByKai";
- }, Android: () => {
- CustomFontEffect.SetFontFileName(lblSample, "abeatbyKaiRegular");
- }, WinPhone: () => {
- lblItalics.FontFamily = "/Assets/Fonts/abeatbyKaiRegular.ttf#AbeatByKai";
- });
Changes in iOS project
Implementation of custom fonts in iOS is pretty straitforward, so just mentioning about the same for the sake of documentation,
- Copy the the custom fonts you need to use in ‘Resources’ folder in iOS specific project as shown in the below screenshot (I kept the file in a separate folder; for the sake of clarity you can put them directly in ‘Resources’ folder also if you want)
- Change the ‘Build Action’ property of every font file as ‘BundleResource’ and ‘Copy to output directory’ to ‘always copy’,
- Open the ‘info.plist’ file in XML editor by right clicking on it and selecting ‘Open With’ option and then selecting XML (Text) Editor from the list of editors given as shown in the below screenshots,
- Add new XML key element ‘UIAppFonts’ and list your custom fonts in array in ‘info.plist’ as per the following screenshot.
That’s it -- your iOS application is ready for showing the custom fonts; no effect implementation is needed for this project.
Changes in Android project
Android project is the main one for which we are writing this blog,
- Copy the the custom fonts you need to use in ‘Assets’ folder in Android specific projects as shown in the below screenshot (I kept the file in a separate folder; for the sake of clarity you can put them directly in ‘Assets’ folder also if you want)
- Change the ‘Build Action’ property of every font file as ‘AndroidAsset’ and ‘Copy to output directory’ to ‘Copy Always’,
- And finally write the implementation for the effect which we have declared in PCL project, for that add a new class file named ‘FontEffect.cs’ to the project and update it with the following code:
- using System;
- using CustomFontEx.Droid;
- using Xamarin.Forms;
- using Xamarin.Forms.Platform.Android;
- using Android.Widget;
- using Android.Graphics;
- using System.ComponentModel;
- [assembly: ResolutionGroupName("Xamarin")]
- [assembly: ExportEffect(typeof(FontEffect), "FontEffect")]
- namespace CustomFontEx.Droid {
- public class FontEffect: PlatformEffect
- {
- TextView control;
- protected override void OnAttached() {
- try {
- control = Control as TextView;
- Typeface font = Typeface.CreateFromAsset(Forms.Context.Assets, "Fonts/" + CustomFontEffect.GetFontFileName(Element) + ".ttf");
- control.Typeface = font;
- } catch (Exception ex) {
- Console.WriteLine("Cannot set property on attached control. Error: ", ex.Message);
- }
- }
- protected override void OnDetached() {}
- protected override void OnElementPropertyChanged(PropertyChangedEventArgs args) {
- if (args.PropertyName == CustomFontEffect.FontFileNameProperty.PropertyName) {
- Typeface font = Typeface.CreateFromAsset(Forms.Context.ApplicationContext.Assets, "Fonts/" + CustomFontEffect.GetFontFileName(Element) + ".ttf");
- control.Typeface = font;
- }
- }
- }
- }
Changes in UWP project
Implementation of custom fonts in UWP is easier & more straitforward than in iOS, so just mentioning about the same for the sake of documentation,
- Copy the the custom fonts you need to use in ‘Assets’ folder in UWP specific project as shown in below screenshot (I kept the file in a separate folder; for the sake of clarity you can put them directly in ‘Assets’ folder also if you want),
- Change the ‘Build Action’ property of every font file as ‘Content’ and ‘Copy to output directory’ to ‘Copy if newer’,
That’s it -- your UWP application is ready for showing the custom fonts, no effect implementation needed for this project.
This is how the sample application whose code is published on Github looks on executing.
iOS Simulator
Android Simulator
Windows 10 Simulator
Let me know if I have missed anything orif you have any suggestions/concerns/queries.