Let's start with Android - you can't set Roboto
font to semi-bold
, since the font doesn't support this weight. Link for reference - Roboto - Google Fonts.
For iOS, San Francisco supports this font weight. Since you are using the built-in system fonts, simply setting the value to .SFUIText-Semibold
should do the trick.
UPDATE
Due to the updated nature of the question, we can have 2 approaches here for iOS. The warning message, that you are getting, says it all:
CoreText note: Client requested name ".SFUIText-Medium", it will get TimesNewRomanPSMT rather than the intended font. All system UI font access should be through proper APIs such as CTFontCreateUIFontForLanguage() or +[UIFont systemFontOfSize:].
This means that in our render, we can set the font like this:
Control.Font = UIFont.SystemFontOfSize(17, UIFontWeight.Medium);
The warning message also says that it can be achieved with CTFont
like so:
new CTFont(".SFUIText-Medium", 17);
For iOS, it is preferrable to use the first approach with SystemFontOfSize
.
NB: Keep in mind that this may not remove the warning message, since very often they are caused from 3rd-party packages, which are still refering to an old Forms version, or are setting the font incorrectly. If this happens, inspect your packages and raise an issue, if necessary. You can take a look at the official commit that fixed this (link). As you can see, they are splitting the string that you've provided and taking the last part. If the last part can be converter to UIFontWeight, they are setting the font the same way as I have just described. So, in the end, if you provide the font as .SFUIText-Medium
in your shared project, it will have the same effect as explicitly refering to it in your custom renderer, because both approaches end up with the same code. Again, you'd want to check your 3rd-party libraries, if the warning persists.
Here's a screenshot with both results - setting the font in the shared project & setting it with a renderer:
For Android you can again set the font in a renderer. Here, you'll need a custom style for this one. In your Android project, create a new style in Resources/values/styles.xml
like this:
<style name="FontRobotoMedium">
<item name="android:fontFamily">sans-serif-medium</item>
<item name="android:textColor">#333333</item>
<item name="android:textSize">17sp</item>
</style>
You can customize a lot here, but for this sample, I have simply addded the family, size & color.
Then, in your renderer, simply change the control's TextAppearance
:
Control.SetTextAppearance(Resource.Style.FontRobotoMedium);
Keep in mind that this can also be achieved without any renderers utilising the power of the system built-in fonts like this:
<Label FontFamily="sans-serif-medium" />
For reference of Android's system fonts, see here.
NB: Keep in mind that Android system fonts are also a subject to a frequent change, so it is again not advisable to use the fonts like this. There's a huge warning at the beginning of fonts.xml
file that I have given a reference to:
WARNING: Parsing of this file by third-party apps is not supported. The
file, and the font files it refers to, will be renamed and/or moved out
from their respective location in the next Android release, and/or the
format or syntax of the file may change significantly. If you parse this
file for information about system fonts, do it at your own risk. Your
application will almost certainly break with the next major Android
release.
Here's a screenshot with both results - setting the font in the shared project & setting it with a renderer:
NOTE: The fonts defer a bit due to a slight difference in the text padding, which can be adjusted in the style like this:
<item name="android:padding">1dip</item>
To sum up, what you can do with a custom renderer, can also be done in the shared project. Under all of the code, the team from Xamarin is doing it very similar (if not the same), as the code from the custom renderer. Don't expect all of the warnings to be gone, since if any 3rd-party library hasn't ungraded to latest forms, or is using the system fonts incorrectly, the warnings will still appear.
Again, it is really not a good practice to try to use the system fonts. They are reserved (and in the case of iOS - hidden behind a dot (.) name) for a reason. In one or two updates, the font may changed and will break the appearance of your app. If you don't have any explicit reason to not import the font files, I'd strongly suggest that you import the font files are refer to them for their families. If you still want to use the system fonts, you can achieve this without any renderers. For iOS simply set the family to .SFUIText-Medium
and for Android - to sans-serif-medium
(both in your shared project).
UPDATE 2
Let's say that you'll set the family as an enum in your shared project. The enum can look like this:
public enum FontFamilyType
{
Light,
Regular,
Medium
}
You can add one additional property in your CustomLabel
wrapper - e.g.
public FontFamilyType FontFamilyType { get; set; }
You can make it bindable property, if necessary.
Here are 2 renderers that take change the font to Regular, Light & Medium. For iOS:
[assembly: ExportRenderer(typeof(CustomLabel), typeof(CustomLabelRenderer))]
namespace FontRenderers.iOS
{
public class CustomLabelRenderer : LabelRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
if (Control != null && Element != null)
{
UIFont font;
switch (Element.FontFamilyType)
{
case FontFamilyType.Light:
font= UIFont.SystemFontOfSize(18, UIFontWeight.Light);
break;
case FontFamilyType.Regular:
font= UIFont.SystemFontOfSize(18, UIFontWeight.Regular);
break;
case FontFamilyType.Medium:
font= UIFont.SystemFontOfSize(18, UIFontWeight.Medium);
break;
default:
throw new ArgumentOutOfRangeException();
}
Control.Font = font;
}
}
}
}
Here I have given the example with all of the 3 requested font families. You can switch them however you'd like - manually, checking some parameters, etc.
For Android:
[assembly: ExportRenderer(typeof(CustomLabel), typeof(CustomLabelRenderer))]
namespace FontRenderer.Droid
{
public class CustomLabelRenderer : LabelRenderer
{
public CustomLabelRenderer(Context context)
: base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
int fontFamilyResId;
switch (Element.FontFamilyType)
{
case FontFamilyType.Light:
fontFamilyResId = Resource.Style.FontRobotoLight;
break;
case FontFamilyType.Regular:
fontFamilyResId = Resource.Style.FontRobotoRegular;
break;
case FontFamilyType.Medium:
fontFamilyResId = Resource.Style.FontRobotoMedium;
break;
default:
throw new ArgumentOutOfRangeException();
}
Control.SetTextAppearance(fontFamilyResId);
}
}
}
Of course, for Android you'll need 2 more styles (for the light & regular families). In styles.xml
add these 2 styles:
<style name="FontRobotoLight">
<item name="android:fontFamily">sans-serif-light</item>
</style>
<style name="FontRobotoRegular">
<item name="android:fontFamily">sans-serif</item>
</style>