在 Xamarin Forms 中,如何将标签的字体设置为 Medium(系统字体)

Ala*_*an2 4 xamarin xamarin.forms

我想使用系统字体SF Pro(iOS)和Roboto(Android)。两者都有中等,但我看不到任何方法来为标签设置这些。

我想我可能需要一个 Label 自定义渲染器,并希望得到任何建议/建议。

以下是一些参考:

https://qiita.com/aqubi/items/3a1e668f4f78d4ad0db7

https://forums.xamarin.com/discussion/97446/set-font-weight-on-label

https://github.com/xamarin/Xamarin.Forms/issues/8035

Mih*_*hev 5

让我们从 Android 开始 - 您不能将Roboto字体设置为semi-bold,因为字体不支持此重量。参考链接 - Roboto - Google 字体

对于 iOS,旧金山支持此字体粗细。由于您使用的是内置系统字体,只需将值设置为即可.SFUIText-Semibold

更新

由于问题的更新性质,我们可以在此处为 iOS 提供 2 种方法。您收到的警告消息说明了一切:

CoreText 注意:客户端请求名称“.SFUIText-Medium”,它将获得 TimesNewRomanPSMT 而不是预期的字体。所有系统 UI 字体访问都应该通过适当的 API,例如 CTFontCreateUIFontForLanguage() 或 +[UIFont systemFontOfSize:]。

这意味着在我们的渲染中,我们可以这样设置字体:

Control.Font = UIFont.SystemFontOfSize(17, UIFontWeight.Medium);
Run Code Online (Sandbox Code Playgroud)

警告消息还说可以CTFont像这样实现:

new CTFont(".SFUIText-Medium", 17);
Run Code Online (Sandbox Code Playgroud)

对于 iOS,最好将第一种方法与SystemFontOfSize.

注意:请记住,这可能不会删除警告消息,因为它们通常是由 3rd-party 包引起的,这些包仍然引用旧的 Forms 版本,或者字体设置不正确。如果发生这种情况,请检查您的包裹并在必要时提出问题。您可以查看修复此问题的官方提交(链接)。如您所见,他们正在拆分您提供的字符串并提取最后一部分。如果最后一部分可以转换为UIFontWeight,那么他们正在以与我刚刚描述的相同的方式设置字体。因此,最后,如果您将字体提供为.SFUIText-Medium在您的共享项目中,它将与在您的自定义渲染器中显式引用它具有相同的效果,因为这两种方法最终都具有相同的代码。同样,如果警告仍然存在,您需要检查您的第 3 方库。

这是包含两个结果的屏幕截图 - 在共享项目中设置字体并使用渲染器设置它: IOS

对于 Android,您可以再次在渲染器中设置字体。在这里,您需要为这个自定义样式。在您的 Android 项目中,创建一个新样式,Resources/values/styles.xml如下所示:

<style name="FontRobotoMedium">
  <item name="android:fontFamily">sans-serif-medium</item>
  <item name="android:textColor">#333333</item>
  <item name="android:textSize">17sp</item>
</style>
Run Code Online (Sandbox Code Playgroud)

您可以在此处进行很多自定义,但对于此示例,我仅添加了系列、尺寸和颜色。

然后,在您的渲染器中,只需更改控件的TextAppearance

Control.SetTextAppearance(Resource.Style.FontRobotoMedium);
Run Code Online (Sandbox Code Playgroud)

请记住,这也可以在没有任何渲染器使用系统内置字体的情况下实现,如下所示:

<Label FontFamily="sans-serif-medium" />
Run Code Online (Sandbox Code Playgroud)

Android 系统字体的参考,请参见此处

注意:请记住,Android 系统字体也​​是经常变化的主题,因此再次不建议使用这样的字体。在fonts.xml文件的开头有一个巨大的警告,我参考了:

警告:不支持第三方应用程序解析此文件。该文件及其引用的字体文件将在下一个 Android 版本中重命名和/或从各自的位置移出,和/或文件的格式或语法可能会发生重大变化。如果您解析此文件以获取有关系统字体的信息,请自行承担风险。您的应用程序几乎肯定会在下一个主要的 Android 版本中崩溃。

这是包含两个结果的屏幕截图 - 在共享项目中设置字体并使用渲染器设置它: 安卓 注意:由于文本填充略有不同,字体会稍微延迟,可以在样式中进行调整,如下所示:

<item name="android:padding">1dip</item>
Run Code Online (Sandbox Code Playgroud)

综上所述,自定义渲染器可以做的事情,在共享项目中也可以做到。在所有代码下,Xamarin 团队的做法与自定义渲染器中的代码非常相似(如果不一样的话)。不要指望所有的警告都会消失,因为如果任何 3rd 方库没有升级到最新形式,或者系统字体使用不正确,警告仍然会出现。

同样,尝试使用系统字体确实不是一个好习惯。它们被保留(在 iOS 的情况下 - 隐藏在点 (.) 名称后面)是有原因的。在一两次更新中,字体可能会发生变化,并会破坏您的应用程序的外观。如果您没有任何明确的理由不导入字体文件,我强烈建议您导入字体文件,请参考它们的家族。如果您仍想使用系统字体,则无需任何渲染器即可实现。对于 iOS,只需将系列设置为.SFUIText-Medium和 Android - to sans-serif-medium(都在您的共享项目中)。

更新 2

假设您将在共享项目中将系列设置为枚举。枚举可以是这样的:

public enum FontFamilyType
{
    Light,
    Regular,
    Medium
}
Run Code Online (Sandbox Code Playgroud)

您可以在CustomLabel包装器中添加一个额外的属性- 例如

public FontFamilyType FontFamilyType { get; set; }
Run Code Online (Sandbox Code Playgroud)

如有必要,您可以使其成为可绑定属性。

这里有 2 个渲染器可以将字体更改为常规、浅色和中等。对于 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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我给出了所有 3 种请求字体系列的示例。您可以随意切换它们 - 手动,检查一些参数等。

对于安卓:

[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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,对于 Android,您还需要 2 种样式(适用于轻型和普通家庭)。在styles.xml添加这些2款:

<style name="FontRobotoLight">
  <item name="android:fontFamily">sans-serif-light</item>
</style>

<style name="FontRobotoRegular">
  <item name="android:fontFamily">sans-serif</item>
</style>

Run Code Online (Sandbox Code Playgroud)