今天开发Flutter时又碰到一个小问题,如何将自定义SVG图标设置到Icon或者说IconData。本以为是一个很简单需求,也搜索到同类需求的 how to import a svg icon to icondata,但回答都没解决这个问题。
花了点时间,终于梳理出这个需求的一些要点,这里分享给有需要的人。
Widget、Icon 和 IconData
首先我们要区别Widget、Icon和IconData,因为很多人觉得 Flutter加载SVG图片是很简单的事,也确实,依赖flutter_svg,然后读取就行。
# 加载SVG图片 https://pub.flutter-io.cn/packages/flutter_svg
flutter_svg: 1.1.6
SvgPicture.asset()
但这里返回的结果是Widget,如果你需要的是Icon或者IconData,它是不能使用的SvgPicture can't be assigned to Icon。

Icon和IconData它们可以当成一类,都是图标,而且Icon是由IconData构造的,可以理解两者之间可以互相转换。

static const IconData abc = IconData(0xf04b6, fontFamily: 'MaterialIcons');
Icon icon = Icon(Icons.abc);
IconData? iconData = Icon(Icons.abc).icon;
所以,关键是IconData,那这个需求就被拆解成,如何从自定义SVG获取IconData。
自定义 IconData
Flutter 内置了一套 Material Design的IconData。在上面代码使用的Icons.abc就是,但这些都是系统级,可能存在不够用的情况,而且大部分公司都有自己设计的图标,这才需要使用自定义 Icon 图标。

这里有个工具网站 FlutterIcon – Flutter custom icons generator,它提供了很多图标,如果内置图标不够用,可以在这找到需要的。

假设找到这 4 个是项目需要的,先别急下载。点击Names重命名。

对着图标重命名,这里的名字是项目中使用这个图标时引用的名字。比如这里的threedee_rotation,那在代码中要用这个图标就是如下。
static const IconData threedee_rotation = IconData(0xe800, fontFamily: _kFontFam, fontPackage: _kFontPkg);
Icon icon = Icon(R.threedee_rotation);
所以,这个名字影响项目中实际使用此图标的命名。第二个名字CustomIcon1也建议自己重命名,不要用默认的,它是fontFamilyName,有三个地方用到了。
flutter:
fonts:
- family: CustomIcon1
fonts:
- asset: fonts/CustomIcon1.ttf
首先,下载到本地的字体图标文件名就是采用这个名字,其次特别重要的fontFamily名字也是用的它。最后,IconData定义时,其中一个参数需要填写fontFamily,它的值也是下载时填写的名字。
static const _kFontFam = 'CustomIcon1';
static const String? _kFontPkg = null;
static const IconData threedee_rotation = IconData(0xe800, fontFamily: _kFontFam, fontPackage: _kFontPkg);
如果上面代码看不清,可以简写成如下:
static const IconData threedee_rotation = IconData(0xe800, fontFamily: "CustomIcon1", fontPackage: null);
OK,这就获取到 IconData了。但不对啊,这里我们还是用网上资源,并不是我们自定义图标。其实上面工具,也提供上传自己的SVG图标,转换下载成图标字体.ttf的功能。

重复上面步骤,不过多了一步上传SVG。
但这是理想状况,实际情况,我们的图标并不是一次性上传,然后下载图标字体.ttf,配置图标。可能先做某个功能,需要用到一些图标,就上传、生成、配置。过了几天,又需要自定义另外一些图标,又来上传下载。
所以,我建议fontFamily按照数字序号命名,因为可能要在pubspec.ymal配置多次,完整代码如下。
flutter:
uses-material-design: true
fonts:
- family: CustomIcon1
fonts:
- asset: assets/fonts/CustomIcon1.ttf
- family: CustomIcon2
fonts:
- asset: assets/fonts/CustomIcon2.ttf
static const IconData treeview_menu_parent = IconData(0xe800, fontFamily: "CustomIcon1", fontPackage: null);
static const IconData treeview_menu_child = IconData(0xe800, fontFamily: "CustomIcon2", fontPackage: null);
当然,可能存在很多图标,上面CustomIcon1建议抽取成变量。然后,貌似引入了新图标文件,要重启整个项目,不能热重载更新。
OK,希望以上能帮到各位,部分参考 How to use custom icons in Flutter。
本文由老郭种树原创,转载请注明:https://guozh.net/how-to-use-custom-icons-in-flutter/