好的 MDL2 设计需要大量的图标。微软通过 Segoe MDL2 Assets 这一图标字体,为我们提供了大量的 MDL2 图标。不过在设计使用中,这些图标往往不能满足我们的需求。这时就需要我们自己制作 MDL2 图标字体,在应用中使用。

问题的由来

本人使用 .NET Core 与 UWP 完成计算机图形学课程的作业。其中一个菜单如下图:

作业程序的菜单,有四个选项,代表直线、圆、椭圆与多边形

不难发现,菜单里面的四个选项,在 Segoe MDL2 Assets 里面并没有对应的图标。于是我需要自制这样的图标。

为什么要使用图标字体

看到这里,有些朋友可能会指出,UWP 中提供了 PathIcon 类,可以通过类似于 SVG 的语法来创建图标,没有必要自己做字体。的确,我所需要的图标样式比较简单,用路径图标可以解决问题。不过使用图标字体有若干好处:

  • 代码更可读
  • 容易绘制更复杂的图形
  • 方便在其它平台上复用
  • 便于我水这篇文章 (雾

当然,制作图标字体的 “Overhead” 也比简单指定路径要高得多。所以…… 自己权衡吧。

MDL2 图标规格

Segoe MDL2 Assets 中的图标都以一个 16 * 16 的网格为底板。这一点,在多年前的 UWP 文档中似乎有提及,但现在在文档中已经找不到相关的说明了。不过如果拿实际的图标对照一下的话,还是能印证这一点。

图中可以看到 MDL2 图标刚好适应 16 乘 16 的网格

于是,我们在创建 MDL2 图标的时候,最好也遵守这样的规范,与设计系统中其它图标统一。例如,我绘制的圆形图标便是一个 128 * 128 的圆,线条宽度为 8, 刚好套在 16 * 16 网格中。

一个刚好适应 16 乘 16 网格的圆形图标

生成图标字体

创建图标字体自然可以使用专门的字体制作工具。但是这类工具学习曲线比较陡,而且大多数很贵,不太适合我这种非专业人员使用。因此,我先使用一般的绘图工具 (这里使用 Affinity Designer) 绘制出图标,再使用其它工具转换成 OpenType 字体。

于是首先要将图标导出出来,供转换工具使用。不过由于 OpenType 字体里面的 Contour 没有粗细的概念,在导出前,需要先将绘制的路径转换为填充。转换好以后,就可以将图标导出成 SVG.

接下来使用 IcoMoon 这一工具,从 SVG 生成 OpenType 图标字体。这一工具的所有转换操作都是在浏览器内进行的,不必担心隐私问题,而且它对于生成的字体也没有什么 License 方面的限制,可以自由使用。

首先戳左上角的 Import Icons 按钮,选择导出的 SVG 图标,图标就会显示在页面上。依次单击这几个图标,将其选中。

完成上面的操作后,显示如图

接下来单击右下角的 Generate Fonts. 此时就会看到我们选择的图标以及对应的 Code Point.

屏幕上会显示图标以及代码位

此时点击上方的 Preferences, 对字体的名称进行设置。例如,我在这里设置为 Plotter-MDL2-Assets. 这个名称后面要用到。

设置生成字体的名称

接下来单击右下角的 Download, 将得到的字体保存下来就好了。

使用图标

下载下来的文件是一个压缩包,在里面的 font 目录下有 SVG, TTF, 与 WOFF 格式的字体。在 UWP 开发中,我们需要使用 TTF. 将这个文件解压出来,放到应用项目的 Assets 目录下面。

然后在 App.xaml 的资源字典中,添加这样的定义:

1
2
3
4
5
6
7
8
9
10
11
12
<FontFamily x:Key="{key}">
/Assets/{filename}#{fontName}
</FontFamily>

<!--
其中 {key} 是资源的键,{filename} 是字体文件的名字,{fontName} 是前面设置的字体名称。例如:

<FontFamily x:Key="PlotterMDL2AssetsFont">
/Assets/Plotter-MDL2-Assets.ttf#Plotter-MDL2-Assets
</FontFamily>

-->

接下来便可以使用这个字体指定图标了:

1
2
3
4
5
6
<MenuFlyoutSubItem Text="Line segment">
<MenuFlyoutSubItem.Icon>
<FontIcon FontFamily="{StaticResource PlotterMDL2AssetsFont}"
Glyph="&#xE900;"/>
</MenuFlyoutSubItem.Icon>
</MenuFlyoutSubItem>

注意要把 FontFamilyGlyph 两个属性替换成实际值。

通过以上步骤,我们就实现了 UWP 中的 “图标自由”。