简体   繁体   中英

load fonts from web on demand

I want to let the user choose the font in my xamarin forms application. I have around 16 fonts which size around 10 MB already my app size is too big this will cause more size. Is there anyway I can download fonts when user want to change the font ? please help.

I've created a sample which does exactly what you need. You can find the source code HERE . Let me explain what I've done.

From architectural perspective we need to do the following

  1. Download font files from backend

  2. Cache those files on device

  3. Make sure they work on iOS and Android. In this step we need to do some device specific tweaking to make the fonts work. For iOS we need to register the fonts with the iOS runtime. For Android we need to create custom renderers for controls for which we want to use custom fonts. Read further for details.

  4. A demo ViewModel and View to demonstrate the functionality.

From code perspective I've done the following to implement above mentioned architecture

Create service for loading fonts

IFontService - service to download and install fonts on local devices

public interface IFontService
    {
        //Directory where we'll keep custom fonts
        IFolder FontFolder { get; }
        //Contains mapping between font name and font file
        Dictionary<string, string> Fonts { get; }
        //Will download and install custom fonts and instantiate the Fonts mapping property
        Task LoadAvailableFonts();
    }

Implement the IFontService

BaseFontService - implements most part of the IFontService which is not device specific. It has two abstract methods which should be implemented device specific for caching and installing fonts.

        //We will cache all the fonts in caches folder, which is device specific, 
        //That's why we use abstract property which we'll implement separately for iOS and android
        //and inject into PCL using dependency injection
        protected abstract Task<IFolder> GetCacheFolder();

        //For iOS we need to register custom fonts with iOS runtime. 
        //Check FontService implementation for more details.
        protected abstract Task InstallFonts(IEnumerable<CustomFont> fonts);

Implement device specific stuff and use dependency injection

In iOS and Android projects I've created FontService implementation which derives from BaseFontService and implements device specific logic - font installation and caching.

Android

For Android we only need to override GetCacheFolder() , we don't need extra installation step for Android, that's why we can leave InstallFonts() implementation empty.

Another tweak that we need for Android is custom renderers for those controls for which we want to use custom font. In iOS this step is not needed, because when you register fonts you can use them all around the application. In my sample I've created ButtonRenderer and LabelRenderer . They simply listen to changes of FontFamily property and then try to find that font using IFontService . I've created a FontToolbox class which which implements font loading logic in TryGetFont method. If you want to support custom fonts for other controls, you can use similar pattern as in Button/Label renderers and use TryGetFont to load actual font.

iOS

For iOS it's bit more complicated. We need to load the font files from the cache directory and register them using ios font management API. Refer here for more details

Demo code

I've created FontDemoViewModel which will call IFontService , load available fonts into a collection to which we'll bind in our view. I've created FontDemoPage which will allow select a font from a picker (for that I've added BindablePickerEx control) and update fonts of a button and a label.

Some notes

Make sure the font file name will match PostScript name of the font. This is not required for Android, because Android will be able to load a font with arbitrary name, because it just needs a reference to a font file. However for iOS you need to make sure this is true, as the run-time searches for fonts by their PostScript name. Here you can find how to get the PostScript name of a font.

Another thing is that in this sample for simplicity sake I've embedded all the fonts into assembly resources. In my BaseFontService I load all the fonts from assembly resources in this method

private async Task<List<CustomFont>> DownloadFonts()

For your implementation you'll need to make actual web requests here to download fonts from your backend.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM