website
website copied to clipboard
Custom fonts CookBook example not working as expected
I added custom fonts to my project following the explanation in https://flutter.dev/docs/cookbook/design/fonts
In the example you can find:
- family: RobotoMono
fonts:
- asset: fonts/RobotoMono-Regular.ttf
- asset: fonts/RobotoMono-Bold.ttf
weight: 700
So I followed it and in my pubspec.yaml
I have:
fonts:
- family: Edmondsans
fonts:
- asset: fonts/Edmondsans-Regular.otf
- asset: fonts/Edmondsans-Medium.otf
weight: 500
- asset: fonts/Edmondsans-Bold.otf
weight: 700
Then in my code:
TextStyle(
fontFamily: "Edmondsans",
fontWeight: FontWeight.w500,
);
However I noticed that:
- The w500 (medium) was not being rendered, and instead, it was rendering the Edmondsans-Regular.
- The w700 (bold) was not rendering Edmondsans-Bold but instead making a bold version of Edmondsans-Regular (they looked different)
To actually use my Medium and Bold custom font files, I had to use them in a different way:
fonts:
- family: Edmondsans
fonts:
- asset: fonts/Edmondsans-Regular.otf
- family: Edmondsans-Medium
fonts:
- asset: fonts/Edmondsans-Medium.otf
- family: Edmondsans-Bold
fonts:
- asset: fonts/Edmondsans-Bold.otf
Then in my code, this will work as expected:
TextStyle(
fontFamily: "Edmondsans-Medium",
);
My configuration info:
[✓] Flutter (Channel beta, v1.7.8+hotfix.3, on Mac OS X 10.14.5 18F132, locale en-DE)
[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 10.3)
[✓] iOS tools - develop for iOS devices
[✓] Android Studio (version 3.4)
[✓] IntelliJ IDEA Ultimate Edition (version 2019.1.3)
[✓] IntelliJ IDEA Community Edition (version 2019.1.3)
[✓] Connected device (1 available)
This issue here seem to be related: https://github.com/flutter/flutter/issues/29806
I'd suggest to change the cookbook examples until custom fonts work as expected.
The Flutter engine matches fonts within a family based on the metadata in the font itself, not the style descriptors declared in the pubspec.yaml
manifest.
(We should remove the style descriptors in pubspec.yaml
now that they are obsolete).
The Edmondsans regular, medium, and bold fonts contain metadata declaring their weights as 400, 410, and 420 respectively. However, the Flutter text subsystem only supports font weight buckets representing even multiples of 100 (https://api.flutter.dev/flutter/dart-ui/FontWeight-class.html). So all three of these fonts are mapped to FontWeight.w400
, and the font style matcher can not choose between these fonts based on weight.
Declaring these fonts as different families in pubspec.yaml
will work around this.
Thanks a lot for the explanation @jason-simmons!
It didn't occur me that my font could have been the one causing this.
I think it would still be good to update the cookbook documentation so it won't confuse other developers.
Moving to the website for the cookbook.
The Flutter engine matches fonts within a family based on the metadata in the font itself, not the style descriptors declared in the
pubspec.yaml
manifest. (We should remove the style descriptors inpubspec.yaml
now that they are obsolete).
Should we update the docs here to explain that these descriptors are actually ignored?
The Flutter engine matches fonts within a family based on the metadata in the font itself, not the style descriptors declared in the
pubspec.yaml
manifest. (We should remove the style descriptors inpubspec.yaml
now that they are obsolete).
This looks like a bug in the flutter engine to me. The font file can, as mentioned, have values between two multiple of 100 (e.g. 425).
The value specified in the pubspec.yaml
should therefore allow us to override that internal value to something we can actually use.
Working with multiple font families as a workaround would work but is far from elegant in my eyes.
Based on what @jason-simmons mentioned, I created the following python script to "fix" your custom font files to use the correct weights that flutter respects. Create a src
directory and put all your fonts in there. Create an empty out
directory and the script will place the new fonts there.
import os
from fontTools import ttLib
# Declare your font file names and the correct weights here
to_change = {
'Neue Radial B Thin Italic.ttf': 100,
'Neue Radial B Thin.ttf': 100,
'Neue Radial B Extra Bold Italic.ttf': 800,
'Neue Radial B Bold.ttf': 700,
'Neue Radial B Book.ttf': 500,
'Neue Radial B Regular Italic.ttf': 400,
'Neue Radial B Light.ttf': 300,
'Neue Radial B Book Italic.ttf': 500,
'Neue Radial B Regular.ttf': 400,
'Neue Radial B Extra Bold.ttf': 800,
'Neue Radial B Extra Light.ttf': 200,
'Neue Radial B Light Italic.ttf': 300,
'Neue Radial B Extra Light Italic.ttf': 200,
'Neue Radial B Bold Italic.ttf': 700,
'Neue Radial B Medium.ttf': 600,
'Neue Radial B Black.ttf': 900,
'Neue Radial B Black Italic.ttf': 900,
'Neue Radial B Medium Italic.ttf': 600,
}
for file, weight in to_change.items():
with ttLib.TTFont(os.path.join('src', file)) as tt:
tt['OS/2'].usWeightClass = weight
tt.save(os.path.join('out',file))
This is probably the best workaround out there at the moment. No multiple font families, and no needing to modify each font individually.
@jason-simmons : Is this font issue still occurring? If so, I can document this workaround. If not, I'll close this issue.
@miquelbeltran, ah the ultimate irony! You filed it, you fix it! :D
Without additional information we're not able to resolve this issue, so it will be closed at this time. You're still free to add more info and respond to any questions above, though. We'll reopen the case if you do. Thanks for your contribution!
I'll work on this now
Is this font issue still occurring? If so, I can document this workaround. If not, I'll close this issue.
For what I can see, Flutter still only supports multiples of 100 when it comes to the font weight.
Reviewing the cookbook recipe, I see that now it says:
Note that defining the
weight
property does not override the actual weight of the font. You would not be able to accessRobotoMono-Bold
withFontWeight.w100
, even if itsweight
was set to 100.
I am thinking, I could add an explanation and workaround in the recipe, e.g.
This can be an issue if the original font file doesn't define its weight as Flutter expects it.
You can workaround this limitation by defining individual font families for each different weight as shown below:
fonts: - family: Edmondsans fonts: - asset: fonts/Edmondsans-Regular.otf - family: Edmondsans-Bold fonts: - asset: fonts/Edmondsans-Bold.otf
And then using them directly in your code:
TextStyle( fontFamily: "Edmondsans-Bold", );
Any thoughts on this? My only concern is that it could be promoting the wrong code practices, so we need to be clear that it is just a workaround for font files that aren't compliant with what Flutter expects.
@miquelbeltran : That works. These docs are fluid, so we can always change again later if this appears to be in error.