In a custom Xamarin Forms iOS renderer I am loading fonts from files and when I get to UIFont.FromName it thorws the exception shown below. The font var is a valid CGFont instance and fontsize is a valid nfloat. Any ideas?
var font = CGFont.CreateFromProvider(fontDataProvider);
Control.Font = UIFont.FromName(font.FullName, (nfloat)e.NewElement.FontSize);
stacktrace:
System.ArgumentNullException: Value cannot be null.
Parameter name: value
at UIKit.UILabel.set_Font (UIKit.UIFont value) [0x00011] in /Users/builder/data/lanes/1381/3afb4af5/source/maccore/src/build/ios/native/UIKit/UILabel.g.cs:337
at DecryptRenderFont.iOS.DecryptRenderControlRenderer.OnElementChanged (Xamarin.Forms.Platform.iOS.ElementChangedEventArgs`1[TElement] e) [0x00215]
at Xamarin.Forms.Platform.iOS.VisualElementRenderer`1[TElement].SetElement (TElement element) [0x00118] in <filename unknown>:0
at Xamarin.Forms.Platform.iOS.VisualElementRenderer`1[TElement].Xamarin.Forms.Platform.iOS.IVisualElementRenderer.SetElement (Xamarin.Forms.VisualElement element) [0x00000] in <filename unknown>:0
at Xamarin.Forms.Platform.iOS.Platform.CreateRenderer (Xamarin.Forms.VisualElement element) [0x0001b] in <filename unknown>:0
at Xamarin.Forms.Platform.iOS.VisualElementPackager.OnChildAdded (Xamarin.Forms.VisualElement view) [0x00000] in <filename unknown>:0
at Xamarin.Forms.Platform.iOS.VisualElementPackager.Load () [0x00023] in <filename unknown>:0
at Xamarin.Forms.Platform.iOS.VisualElementRenderer`1[TElement].SetElement (TElement element) [0x000cc] in <filename unknown>:0
at Xamarin.Forms.Platform.iOS.VisualElementRenderer`1[TElement].Xamarin.Forms.Platform.iOS.IVisualElementRenderer.SetElement (Xamarin.Forms.VisualElement element) [0x00000] in <filename unknown>:0
at Xamarin.Forms.Platform.iOS.Platform.CreateRenderer (Xamarin.Forms.VisualElement element) [0x0001b] in <filename unknown>:0
at Xamarin.Forms.Platform.iOS.VisualElementPackager.OnChildAdded (Xamarin.Forms.VisualElement view) [0x00000] in <filename unknown>:0
at Xamarin.Forms.Platform.iOS.VisualElementPackager.Load () [0x00023] in <filename unknown>:0
at Xamarin.Forms.Platform.iOS.PageRenderer.ViewDidLoad () [0x0007d] in <filename unknown>:0
at (wrapper managed-to-native) ObjCRuntime.Messaging:IntPtr_objc_msgSendSuper (intptr,intptr)
at UIKit.UIViewController.get_View () [0x00030] in /Users/builder/data/lanes/1381/3afb4af5/source/maccore/src/build/ios/native/UIKit/UIViewController.g.cs:2667
1 ) I am going to assume the exception stack you are seeing is not showing the actual underlaying error as it is coming from the Xamarin.iOS
generated UILabel.g.cs
file (that is a auto-generated wrapper within https://github.com/xamarin/xamarin-macios) and I personally have had a few issues tracing certain low-level OS exceptions/throws and thus the shown exception is a little (a lot?) misleading.
2) Again I am going to assume since you said you are "loading fonts from files" that these fonts are not registered. Assuming you are loading these fonts via a CGFont.CreateFromProvider
from files in your app bundle (or dynimically downloaded) and since they do not exist in the info.plist under the UIAppFonts
key, they are not auto-registered to iOS. You need to do that step yourself:
NSError error;
if (!CTFontManager.RegisterGraphicsFont(customFont, out error))
{
// error occurred, checkout the contents of the NSError var
}
After registering the CGFont with the iOS font manager (CTFontManager
) you can actually use them within UIKit
, otherwise internally there is an exception within iOS code... Would need to write some ObjC/Swift to check it out in Xcode to see what the actual error being thrown is...
Are your fonts registered or not:
Somewhere before the exception but after your CreateFromProvider
, you can do the following:
foreach (var familyNames in UIFont.FamilyNames.OrderBy(c => c).ToList())
{
D.WriteLine(" * " + familyNames);
foreach (var familyName in UIFont.FontNamesForFamilyName(familyNames).OrderBy(c => c).ToList())
{
D.WriteLine(" *-- " + familyName);
}
}
Note: D
is just using D = System.Diagnostics.Debug;
I would bet that your font is not in the list, but after a call to CTFontManager.RegisterGraphicsFont
it will be in that list and valid to be consumed by UIKit
.
Update:
Interesting note in that using a Swift-based app and not registering the font does not cause a app crash. The font is not shown of course, but referencing it via UIFont(name: "XXXXX", size: 35)
is just a silent failure.
So I'd just recommend some defensive try{} catch{}
around any use of your custom font to be safe.
Xamarin.iOS - Custom Fonts
- iOS only supports .TTF and .OTF font types.
- Add the fonts to the 'Resources/Fonts/' folder (any folder would do but lets keep it organized).
- Right click on the added font, 'Properties', change ‘Copy to output directory’ to ‘Always copy’.
- Open the Info.plist file and select ‘Source’ at the bottom of the view.
- ‘Add new entry’, select ‘Fonts provided by application’.
- Input the location of the font ‘Fonts/FontName.ttf’.
- Use it:
lab1.Font = UIFont.FromName("FontName", 20f);
All credit goes to Mike James - custom-fonts-in-ios.
To add to Eyal/Mike James answer. Its important that you use the right FontName
. If you open your font files info, you may see that the file name is different from your Full Name
.
In the image below you can see the File name is FranklinGothicMedium.otf
but the full name is FranklinGothicURW-Med
. You must use the full name when using UIFont.FromName([YourFontFullName], 20f);
.