Xamarin.forms: FontImageSource Issue on navigation

Created on 27 May 2019  路  18Comments  路  Source: xamarin/Xamarin.Forms

Description

When FontImageSource is used in a page along with font icon for Button.Text property, on navigating back from that page and loading that page again font icon is displayed as box in Android.

Steps to Reproduce

  1. Open page with FontImageSource and Button with FontIcon
  2. Return from the page
  3. Repeat step 1, FontIcon will be displayed as box

Expected Behavior

Font icon should be displayed properly always.

Actual Behavior

Font icon is displayed as box after navigation

Screenshots

Screenshot_20190527-123537

After navigation:

Screenshot_20190527-123553

Reproduction Link

https://github.com/divi1411/FontIconSample

5 Android bug

Most helpful comment

@akuehntopf Confirmed!
To workaround this issue until its fixed you can register your custom font image source handler in android project like this:

```c#
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Android.Content;
using Android.Graphics;
using Android.Util;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Color = Xamarin.Forms.Color;

[assembly: ExportImageSourceHandler(typeof(FontImageSource), typeof(MyApp.Droid.Helpers.FontImageSourceHandler))]

namespace MyApp.Droid.Helpers
{
public sealed class FontImageSourceHandler : IImageSourceHandler
{
private static Dictionary TypefaceCache = new Dictionary();

    public Task<Bitmap> LoadImageAsync(
        ImageSource imagesource,
        Context context,
        CancellationToken cancelationToken = default(CancellationToken))
    {
        Bitmap image = null;
        var fontsource = imagesource as FontImageSource;
        if (fontsource != null)
        {
            var paint = new Paint
            {
                TextSize = TypedValue.ApplyDimension(ComplexUnitType.Dip, (float)fontsource.Size, context.Resources.DisplayMetrics),
                Color = (fontsource.Color != Color.Default ? fontsource.Color : Color.White).ToAndroid(),
                TextAlign = Paint.Align.Left,
                AntiAlias = true
            };

            if (!TypefaceCache.TryGetValue(fontsource.FontFamily, out Typeface typeface))
            {
                typeface = fontsource.FontFamily.ToTypeFace();
                TypefaceCache.Add(fontsource.FontFamily, typeface);
            }
            paint.SetTypeface(typeface);

            var width = (int)(paint.MeasureText(fontsource.Glyph) + .5f);
            var baseline = (int)(-paint.Ascent() + .5f);
            var height = (int)(baseline + paint.Descent() + .5f);
            image = Bitmap.CreateBitmap(width, height, Bitmap.Config.Argb8888);
            var canvas = new Canvas(image);
            canvas.DrawText(fontsource.Glyph, 0, baseline, paint);
        }

        return Task.FromResult(image);
    }
}

}
```

Also need to copy FontExtensions.cs from https://github.com/xamarin/Xamarin.Forms/blob/5716f8d75704328a8a73a1bfdc83e37e55d5d662/Xamarin.Forms.Platform.Android/Renderers/FontExtensions.cs to your android project

All 18 comments

I've got a related issue, where using fonts as image sources breaks them when used as text in other locations in the app. It can randomly fail in different bits of the app.

The workaround was to have two instances of the font file, one just used for font image sources and one just for using as text. Seems like some file access issue?

Confirmed, i've got this issue too

It's not button specific, I also have this issue for ImageButton and Label
@samhouts Could you add blocking label to it? I think it blocks using FontImageSource

After digging around a bit in FontImageSource's code it seems that the culprit is the using block which releases the typeface (https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Platform.Android/Renderers/FontImageSourceHandler.cs#L29).

If i move the call in line 30 out of the using-block it starts working as expected. Of course then, as there is apparently no caching of the created Typefaces (.CreateFromAsset() call, see FontExtensions.cs) this might lead to memory leaks or poor performance (could probably be solved with a typeface cache dict).

Can somebody please confirm this?

@akuehntopf Confirmed!
To workaround this issue until its fixed you can register your custom font image source handler in android project like this:

```c#
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Android.Content;
using Android.Graphics;
using Android.Util;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Color = Xamarin.Forms.Color;

[assembly: ExportImageSourceHandler(typeof(FontImageSource), typeof(MyApp.Droid.Helpers.FontImageSourceHandler))]

namespace MyApp.Droid.Helpers
{
public sealed class FontImageSourceHandler : IImageSourceHandler
{
private static Dictionary TypefaceCache = new Dictionary();

    public Task<Bitmap> LoadImageAsync(
        ImageSource imagesource,
        Context context,
        CancellationToken cancelationToken = default(CancellationToken))
    {
        Bitmap image = null;
        var fontsource = imagesource as FontImageSource;
        if (fontsource != null)
        {
            var paint = new Paint
            {
                TextSize = TypedValue.ApplyDimension(ComplexUnitType.Dip, (float)fontsource.Size, context.Resources.DisplayMetrics),
                Color = (fontsource.Color != Color.Default ? fontsource.Color : Color.White).ToAndroid(),
                TextAlign = Paint.Align.Left,
                AntiAlias = true
            };

            if (!TypefaceCache.TryGetValue(fontsource.FontFamily, out Typeface typeface))
            {
                typeface = fontsource.FontFamily.ToTypeFace();
                TypefaceCache.Add(fontsource.FontFamily, typeface);
            }
            paint.SetTypeface(typeface);

            var width = (int)(paint.MeasureText(fontsource.Glyph) + .5f);
            var baseline = (int)(-paint.Ascent() + .5f);
            var height = (int)(baseline + paint.Descent() + .5f);
            image = Bitmap.CreateBitmap(width, height, Bitmap.Config.Argb8888);
            var canvas = new Canvas(image);
            canvas.DrawText(fontsource.Glyph, 0, baseline, paint);
        }

        return Task.FromResult(image);
    }
}

}
```

Also need to copy FontExtensions.cs from https://github.com/xamarin/Xamarin.Forms/blob/5716f8d75704328a8a73a1bfdc83e37e55d5d662/Xamarin.Forms.Platform.Android/Renderers/FontExtensions.cs to your android project

After some testing in my project, I created PR that fixes the issue

@toomasz You code broke my FontImageSource but fixed my Label (+ Glyph font).

This also happens when using FontImageSource on ToolbarItem.IconImageSource. Navigating to a page that has the icon with FontImageSource breaks text from both Label and Button in the page. Any update on this?

Is there an estimate to the official fix to this? This bug makes shell unusable

Thanks, the bug is fixed on the last Xamarin version.

That is great to hear @matthieume! Good luck using it in your projects! :D

Hi!
This hotfix does not work for Label:
<Label x:Name="iconPriceTotal" FontFamily="{StaticResource FontAwesomeSolid}" Text="&#xf07a;" FontSize="14" TextColor="#f98e02"></Label>

Is there anything known about this?

@samhouts: The bug is fixed for most controls in the latest Xamarin version, but this is still an issue, when a FontImageSource is used as Shell.FlyoutIcon or SearchHandler.QueryIcon.

@ArgusMagnus if it's not too much trouble could you please check if there is already an issue for this. If not, open a new one. That way we can better track that isolated issue.

Thanks!

@toomasz good job with your PR! Maybe update your workarround to use ConcurrentDictionary for Typeface Cache? At least you changed it for your PR as well

FontImageSource is not working at all anymore for Android on 4.5 and on recent 4.4 versions.

It fails with "width and height must be > 0"

I reverted to 4.4.0.1203-nightly and it's working again.

@wagenheimer please check if there is an issue for this or open one if there isn鈥檛. If you could add a reproduction that would be amazing, thanks!

@jfversluis I just tested with Xamarin Form 4.5pre2 and the bug remains.
Here is an example where it happens.
https://www.dropbox.com/s/s2olx9bga5m18sk/ShellIconProblem.zip?dl=0

Execute the Android Build.... you will see "width and height must be > 0" errors and no Icons on Flyout.

I can confirm that everything was working at least until 4.4.0.1203-nightly.

I created a bug report to it!
https://github.com/xamarin/Xamarin.Forms/issues/9371

Was this page helpful?
0 / 5 - 0 ratings