我创建了一个完全符合您需要的示例。你可以找到源代码HERE。让我解释一下我做了什么。
从架构的角度来看,我们需要做以下事情
从后端下载字体文件
在设备上缓存这些文件
确保它们可以在 iOS 和 Android 上运行。在这一步中,我们需要进行一些特定于设备的调整以使字体正常工作。对于 iOS,我们需要在 iOS 运行时注册字体。对于 Android,我们需要为要使用自定义字体的控件创建自定义渲染器。进一步阅读了解详情。
一个演示 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 项目中,我创建了源自 BaseFontService 的 FontService 实现,并实现了设备特定的逻辑 - 字体安装和缓存。
Android
对于Android,我们只需要覆盖GetCacheFolder(),我们不需要额外的Android安装步骤,这就是为什么我们可以将InstallFonts()的实现留空。
我们需要为 Android 进行的另一项调整是为我们想要使用自定义字体的控件自定义渲染器。在 iOS 中,不需要此步骤,因为当您注册字体时,您可以在整个应用程序中使用它们。在我的示例中,我创建了ButtonRenderer 和LabelRenderer。他们只需监听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()
对于您的实施,您需要在此处发出实际的网络请求以从您的后端下载字体。