【问题标题】:load fonts from web on demand按需从网络加载字体
【发布时间】:2016-05-27 23:51:02
【问题描述】:

我想让用户在我的 xamarin 表单应用程序中选择字体。我有大约 16 种字体,大小约为 10 MB,我的应用程序已经太大了,这将导致更大的大小。当用户想要更改字体时,我可以下载字体吗?请帮忙。

【问题讨论】:

  • 我认为自定义字体必须包含在 app bundle 中
  • @Jason 我知道但正在寻找更多的可能性。我知道我们可以创建资产目录并将它们与包分开下载。但不确定字体是否可以这样做。还需要为其他平台想办法。
  • 我的立场是正确的 - 也许这在 iOS 中是可能的。见stackoverflow.com/questions/19776285/…
  • @Jason 看起来不错,但我们只能使用列出的字体,这在我的情况下是不可行的

标签: xamarin.forms custom-font ondemand


【解决方案1】:

我创建了一个完全符合您需要的示例。你可以找到源代码HERE。让我解释一下我做了什么。

从架构的角度来看,我们需要做以下事情

  1. 从后端下载字体文件

  2. 在设备上缓存这些文件

  3. 确保它们可以在 iOS 和 Android 上运行。在这一步中,我们需要进行一些特定于设备的调整以使字体正常工作。对于 iOS,我们需要在 iOS 运行时注册字体。对于 Android,我们需要为要使用自定义字体的控件创建自定义渲染器。进一步阅读了解详情。

  4. 一个演示 ViewModel 和 View 来演示功能。

从代码的角度来看,我已经完成了以下操作来实现上述架构

创建加载字体的服务

IFontService - 在本地设备上下载和安装字体的服务

public interface IFontService
    {
        //Directory where we'll keep custom fonts
        IFolder FontFolder { get; }
        //Contains mapping between font name and font file
        Dictionary<string, string> Fonts { get; }
        //Will download and install custom fonts and instantiate the Fonts mapping property
        Task LoadAvailableFonts();
    }

实现IFontService

BaseFontService - 实现IFontService 的大部分,这不是设备特定的。它有两个抽象方法,应该实现特定于缓存和安装字体的设备。

        //We will cache all the fonts in caches folder, which is device specific, 
        //That's why we use abstract property which we'll implement separately for iOS and android
        //and inject into PCL using dependency injection
        protected abstract Task<IFolder> GetCacheFolder();

        //For iOS we need to register custom fonts with iOS runtime. 
        //Check FontService implementation for more details.
        protected abstract Task InstallFonts(IEnumerable<CustomFont> fonts);

实现设备特定的东西并使用依赖注入

在 iOS 和 Android 项目中,我创建了源自 BaseFontServiceFontService 实现,并实现了设备特定的逻辑 - 字体安装和缓存。

Android

对于Android,我们只需要覆盖GetCacheFolder(),我们不需要额外的Android安装步骤,这就是为什么我们可以将InstallFonts()的实现留空。

我们需要为 Android 进行的另一项调整是为我们想要使用自定义字体的控件自定义渲染器。在 iOS 中,不需要此步骤,因为当您注册字体时,您可以在整个应用程序中使用它们。在我的示例中,我创建了ButtonRendererLabelRenderer。他们只需监听FontFamily 属性的变化,然后尝试使用IFontService 查找该字体。我创建了一个FontToolbox 类,它在TryGetFont 方法中实现字体加载逻辑。如果您想支持其他控件的自定义字体,您可以使用与 Button/Label 渲染器中类似的模式,并使用 TryGetFont 加载实际字体。

iOS

对于 iOS,它有点复杂。我们需要从缓存目录加载字体文件并使用 ios 字体管理 API 注册它们。更多详情请参考here

演示代码

我创建了 FontDemoViewModel,它将调用 IFontService,将可用字体加载到我们将在视图中绑定到的集合中。 我创建了 FontDemoPage,它允许从选择器中选择一种字体(为此我添加了 BindablePickerEx 控件)并更新按钮和标签的字体。

一些注意事项

确保字体文件名与字体的 PostScript 名称匹配。这对于 Android 来说不是必需的,因为 Android 将能够加载具有任意名称的字体,因为它只需要对字体文件的引用。但是对于 iOS,您需要确保这是真的,因为运行时会通过 PostScript 名称搜索字体。 Here你可以找到如何获取字体的 PostScript 名称。

另一件事是,在这个示例中,为了简单起见,我已将所有字体嵌入到程序集资源中。在我的BaseFontService 中,我使用此方法从程序集资源中加载所有字体

private async Task<List<CustomFont>> DownloadFonts()

对于您的实施,您需要在此处发出实际的网络请求以从您的后端下载字体。

【讨论】:

    猜你喜欢
    • 2011-06-13
    • 2016-03-13
    • 2015-09-17
    • 2018-11-13
    • 2011-09-26
    • 2012-11-03
    • 2011-10-17
    • 1970-01-01
    • 2018-07-07
    相关资源
    最近更新 更多