我想让用户在我的 xamarin 表单应用程序中选择字体。我有大约 16 种字体,大小约为 10 MB,我的应用程序已经太大了,这将导致更大的大小。当用户想要更改字体时,我可以下载字体吗?请帮忙。
1 回答
我创建了一个完全符合您需要的示例。你可以在这里找到源代码。让我解释一下我做了什么。
从架构的角度来看,我们需要做以下事情
从后端下载字体文件
在设备上缓存这些文件
确保它们可以在 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 项目中,我创建了从设备特定逻辑FontService
派生并实现的实现 - 字体安装和缓存。BaseFontService
安卓
对于Android,我们只需要覆盖GetCacheFolder()
,我们不需要额外的Android安装步骤,这就是我们可以将InstallFonts()
实现留空的原因。
我们需要对 Android 进行的另一个调整是为那些我们想要使用自定义字体的控件自定义渲染器。在 iOS 中,不需要此步骤,因为当您注册字体时,您可以在整个应用程序中使用它们。在我的示例中,我创建了ButtonRenderer
和LabelRenderer
. 他们只是监听FontFamily
属性的变化,然后尝试使用IFontService
. 我创建了一个FontToolbox
在方法中实现字体加载逻辑的类TryGetFont
。如果您想支持其他控件的自定义字体,您可以使用与 Button/Label 渲染器中类似的模式并用于TryGetFont
加载实际字体。
iOS
对于 iOS,它有点复杂。我们需要从缓存目录加载字体文件并使用 ios 字体管理 API 注册它们。请参阅此处了解更多详情
演示代码
我创建了 FontDemoViewModel,它将调用IFontService
,将可用字体加载到我们将在视图中绑定到的集合中。我创建了 FontDemoPage,它允许从选择器中选择一种字体(为此我添加了BindablePickerEx
控件)并更新按钮和标签的字体。
一些笔记
确保字体文件名与字体的 PostScript 名称匹配。这对于 Android 来说不是必需的,因为 Android 将能够加载具有任意名称的字体,因为它只需要对字体文件的引用。但是对于 iOS,您需要确保这是真的,因为运行时会通过 PostScript 名称搜索字体。在这里您可以找到如何获取字体的 PostScript 名称。
另一件事是,在此示例中,为了简单起见,我已将所有字体嵌入到程序集资源中。在我BaseFontService
的这个方法中,我从程序集资源中加载了所有字体
private async Task<List<CustomFont>> DownloadFonts()
对于您的实施,您需要在此处发出实际的 Web 请求以从后端下载字体。