在移动应用开发中,字体的个性化设置是一个常见的需求。Xamarin.Forms提供了自定义字体机制,但需要为每个平台单独声明,这在实际项目中显得不够高效。本文将介绍如何创建一个跨平台的字体管理器,以及如何为 Android 和 iOS 创建自定义渲染器,以实现统一的字体调用方式。
首先,需要创建一个名为 FontManager 的帮助类,用于在 Android 项目中管理字体。将这个类设计为单例模式,并使用一个字典来存储字体对象。
private IDictionary<string, Typeface> _typefaces = null;
protected FontManager()
{
_typefaces = new Dictionary<string, Typeface>();
}
private static FontManager _current = null;
public static FontManager Current
{
get
{
return _current ?? (_current = new FontManager());
}
}
接下来,需要创建一个函数来注册字体文件和字体名称。这个函数将字体文件的路径和名称作为参数,并在字典中存储 Typeface 对象。
private FontManager RegisterTypeFace(string fontName, string fontPath)
{
Typeface newTypeface = null;
try
{
newTypeface = Typeface.CreateFromAsset(
Application.Context.Assets,
fontPath);
}
catch (Exception ex)
{
Console.WriteLine("Typeface service: " + ex);
newTypeface = Typeface.Default;
}
_typefaces.Add(fontName, newTypeface);
return this;
}
为了简化操作,还可以创建一个只使用 fontPath 作为参数的函数,并自动猜测字体名称。
public FontManager RegisterTypeFace(string fontPath)
{
var fontName = System.IO.Path.GetFileNameWithoutExtension(fontPath);
Console.WriteLine("fontName: " + fontName);
return RegisterTypeFace(fontName, fontPath);
}
现在可以注册任意数量的字体。接下来,需要一个函数来获取这些字体,以便在控件中使用。这个函数非常简单,只需要在字典对象中查找即可。
public Typeface GetTypeface(string fontName)
{
if (!_typefaces.ContainsKey(fontName))
{
RegisterTypeFace(
fontName,
string.Format("Fonts/{0}.ttf", fontName));
}
return _typefaces[fontName];
}
在本教程中,将为Xamarin.Forms控件创建三个自定义渲染器:Label、Entry 和 Button。这些渲染器的实现相似,都是在 OnElementPropertyChanged 和 OnElementChanged 事件中替换字体。
以下是 Button 渲染器的实现示例:
[assembly: ExportRenderer(typeof(Button), typeof(CustomButtonRenderer))]
namespace CustomFont.Droid.Renderers
{
public class CustomButtonRenderer : ButtonRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (Element == null) return;
if (Control == null) return;
ChangeFont();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (Element == null) return;
if (Control == null) return;
if (e.PropertyName == Button.FontFamilyProperty.PropertyName)
{
ChangeFont();
}
}
private void ChangeFont()
{
Control.TransformationMethod = (null);
var typeface = string.IsNullOrEmpty(Element.FontFamily) ?
Typeface.Default :
FontManager.Current.GetTypeface(Element.FontFamily);
Control.Typeface = typeface;
}
}
}
Entry 和 Label 渲染器的实现与 Button 类似,这里不再赘述。
在准备好自定义字体管理器和自定义渲染器后,可以开始在项目中使用自定义字体了。首先,需要下载一些字体文件,例如从 Google Fonts 服务获取 Oswald-Regular 和 Pangolin 字体。
将字体文件添加到 Droid/Assets 文件夹中,然后在 MainActivity.cs 中注册这些字体:
FontManager.Current.RegisterTypeFace("Fonts/Oswald/Oswald-Regular.ttf")
.RegisterTypeFace("Fonts/Pangolin/Pangolin-Regular.ttf");
注册字体后,可以通过更改 FontFamily 属性来使用这些字体,而无需添加 OnPlatform 选择器。以下是一个使用 XAML 创建的示例 UI:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:CustomFont" x:Class="CustomFont.CustomFontPage">
<StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="Fill" Padding="10,10,10,10">
<Label Text="Welcome to Xamarin Forms!" FontFamily="Pangolin-Regular" HorizontalOptions="Center" />
<Entry Text="Edit Me" FontFamily="Pangolin-Regular" HorizontalOptions="Fill" HorizontalTextAlignment="Start" />
<Button Text="Click Me" FontFamily="Oswald-Regular" HorizontalOptions="Center" />
</StackLayout>
</ContentPage>
在 Android 设备或模拟器上运行时,应该可以看到以下效果:
在 iOS 上运行时,将显示与 Android 相同的字体。因此,下次想要更改控件的字体时,可以轻松地进行更改。