提供包时,自定义字体不会呈现为金色图像
Custom font is not rendered to golden images when package is provided
我在模块 theme
中定义了自定义字体。该模块是模块 widgets
中的依赖项。
小部件模块中的一个小部件应用了如下自定义字体
style: TextStyle(
fontSize: fontSize,
fontFamily: "IconActions",
package: "theme"
)
它工作正常。
遗憾的是,此自定义字体未在金色图像上呈现。我必须删除 package: "theme"
才能解决这个问题。但这会破坏应用程序并且不再显示字体。
所以基本上我可以让字体在生产代码或测试代码中正常工作,但不能同时使用。
自定义字体在测试的setUp
方法中加载
final fontData = File('assets/fonts/IconActions.ttf')
.readAsBytes()
.then((bytes) => ByteData.view(Uint8List.fromList(bytes).buffer));
final fontLoader = FontLoader('IconActions')..addFont(fontData);
await fontLoader.load();
我是不是遗漏了什么,或者这是一个错误?
所以基本上解决方案是从 TextStyle 中删除 package: "theme"
以使其工作。但这只是解决方案的一半,因为正如我在问题中提到的,现在黄金文件具有正确的字体渲染器,但字体在应用程序中不起作用。
要使其在应用程序中运行,我们需要给定项目结构:
pubspec.yaml(模块 theme
)
flutter:
fonts:
- family 'ComicSans'
fonts:
- asset: packages/theme/fonts/ComicSans.ttf
widget.dart(模块 theme
)
style: TextStyle(
fontSize: fontSize,
fontFamily: "ComicSans",
)
现在在模块 widgets
中,这是包含 main.dart
及其 main
功能的模块,您 运行,您必须再次定义字体:
pubspec.yaml(模块 widgets
)
dependencies:
flutter:
sdk: flutter
theme:
path: ../path/to/theme/module
flutter:
fonts:
- family 'ComicSans'
fonts:
- asset: packages/theme/fonts/ComicSans.ttf
现在字体在应用程序和金色图像中都可以正确显示。
去年我遇到过这个确切的问题,也无法在测试中加载字体。不知道是 package
参数破坏了它,所以感谢您更新该结果。
至于另一种解决方法,有一种方法可以两全其美,您可以拥有独立的字体包,而不必在使用它的应用程序中声明打包的字体文件。
例如,我们有一个公司 branding/typography 包,我们在多个应用程序中使用它,其中包含我们所有的预配置 TextStyle
声明,以及另一个自定义生成的独立包 IconData
存储在 *.ttf
文件中(如 FontAwesome)。
包装方:
pubspec.yaml
flutter:
uses-material-design: true
assets:
- assets/fonts/
fonts:
- family: MyFont
fonts:
- asset: assets/fonts/MyFont.ttf
weight: 400
# etc
打包后TextStyle
:
class BrandStyles {
static const _packageName = '<package_name>';
static const headline1Style = TextStyle(
color: Colors.black,
fontFamily: 'MyFont',
fontSize: 60.0,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w400,
height: 1.16,
letterSpacing: 0,
package: _packageName,
);
// etc
}
黄金测试
void main() {
final widget = MaterialApp(
theme: ThemeData(
textTheme: TextTheme(
// use custom extension method to remove `package` value
headline1: BrandStyles.headline1Style.trimFontPackage(),
),
),
home: Scaffold(
body: SafeArea(child: StylesExample()),
),
);
setUp(() async {
TestWidgetsFlutterBinding.ensureInitialized();
final file = File('path/to/packaged/asset/MyFont.ttf').readAsBytesSync();
final bytes = Future<ByteData>.value(file.buffer.asByteData());
await (FontLoader('MyFont')..addFont(bytes)).load();
});
testWidgets('Golden typography test', (WidgetTester tester) async {
await tester.pumpWidget(widget);
await expectLater(
find.byType(MaterialApp), matchesGoldenFile('goldens/typography.png'));
});
}
extension StylingExtensions on TextStyle {
TextStyle trimFontPackage() {
return TextStyle(
inherit: inherit,
color: color,
backgroundColor: backgroundColor,
fontSize: fontSize,
fontWeight: fontWeight,
fontStyle: fontStyle,
letterSpacing: letterSpacing,
wordSpacing: wordSpacing,
textBaseline: textBaseline,
height: height,
locale: locale,
foreground: foreground,
background: background,
shadows: shadows,
fontFeatures: fontFeatures,
decoration: decoration,
decorationColor: decorationColor,
decorationStyle: decorationStyle,
decorationThickness: decorationThickness,
debugLabel: debugLabel,
/// `replaceAll` only required if loading multiple fonts,
/// otherwise set value to your single `fontFamily` name
fontFamily: fontFamily.replaceAll('packages/<package_name>/', ''),
);
}
}
或者如果像我一样,自定义图标也有同样的问题,同样可以在您的自定义 IconData
黄金测试中使用类似的扩展方法来完成,删除 fontPackage
值:
extension IconExtensions on IconData {
IconData convertToGolden() => IconData(
this.codePoint,
fontFamily: this.fontFamily,
);
}
您的应用端
pubspec.yaml
# ...
dependencies:
flutter:
sdk: flutter
<package_name>:
git:
url: <url_to_hosted_package>.git
ref: <release_tag>
main.dart
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData.light().copyWith(
textTheme: TextTheme(
headline1: BrandStyles.headline1Style,
),
),
);
}
}
现在不再需要在您的应用程序中声明您的字体 pubspec.yaml
,甚至不需要在与您的实施应用程序相同的 project/repository 中拥有样式包。
我在模块 theme
中定义了自定义字体。该模块是模块 widgets
中的依赖项。
小部件模块中的一个小部件应用了如下自定义字体
style: TextStyle(
fontSize: fontSize,
fontFamily: "IconActions",
package: "theme"
)
它工作正常。
遗憾的是,此自定义字体未在金色图像上呈现。我必须删除 package: "theme"
才能解决这个问题。但这会破坏应用程序并且不再显示字体。
所以基本上我可以让字体在生产代码或测试代码中正常工作,但不能同时使用。
自定义字体在测试的setUp
方法中加载
final fontData = File('assets/fonts/IconActions.ttf')
.readAsBytes()
.then((bytes) => ByteData.view(Uint8List.fromList(bytes).buffer));
final fontLoader = FontLoader('IconActions')..addFont(fontData);
await fontLoader.load();
我是不是遗漏了什么,或者这是一个错误?
所以基本上解决方案是从 TextStyle 中删除 package: "theme"
以使其工作。但这只是解决方案的一半,因为正如我在问题中提到的,现在黄金文件具有正确的字体渲染器,但字体在应用程序中不起作用。
要使其在应用程序中运行,我们需要给定项目结构:
pubspec.yaml(模块 theme
)
flutter:
fonts:
- family 'ComicSans'
fonts:
- asset: packages/theme/fonts/ComicSans.ttf
widget.dart(模块 theme
)
style: TextStyle(
fontSize: fontSize,
fontFamily: "ComicSans",
)
现在在模块 widgets
中,这是包含 main.dart
及其 main
功能的模块,您 运行,您必须再次定义字体:
pubspec.yaml(模块 widgets
)
dependencies:
flutter:
sdk: flutter
theme:
path: ../path/to/theme/module
flutter:
fonts:
- family 'ComicSans'
fonts:
- asset: packages/theme/fonts/ComicSans.ttf
现在字体在应用程序和金色图像中都可以正确显示。
去年我遇到过这个确切的问题,也无法在测试中加载字体。不知道是 package
参数破坏了它,所以感谢您更新该结果。
至于另一种解决方法,有一种方法可以两全其美,您可以拥有独立的字体包,而不必在使用它的应用程序中声明打包的字体文件。
例如,我们有一个公司 branding/typography 包,我们在多个应用程序中使用它,其中包含我们所有的预配置 TextStyle
声明,以及另一个自定义生成的独立包 IconData
存储在 *.ttf
文件中(如 FontAwesome)。
包装方:
pubspec.yaml
flutter:
uses-material-design: true
assets:
- assets/fonts/
fonts:
- family: MyFont
fonts:
- asset: assets/fonts/MyFont.ttf
weight: 400
# etc
打包后TextStyle
:
class BrandStyles {
static const _packageName = '<package_name>';
static const headline1Style = TextStyle(
color: Colors.black,
fontFamily: 'MyFont',
fontSize: 60.0,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w400,
height: 1.16,
letterSpacing: 0,
package: _packageName,
);
// etc
}
黄金测试
void main() {
final widget = MaterialApp(
theme: ThemeData(
textTheme: TextTheme(
// use custom extension method to remove `package` value
headline1: BrandStyles.headline1Style.trimFontPackage(),
),
),
home: Scaffold(
body: SafeArea(child: StylesExample()),
),
);
setUp(() async {
TestWidgetsFlutterBinding.ensureInitialized();
final file = File('path/to/packaged/asset/MyFont.ttf').readAsBytesSync();
final bytes = Future<ByteData>.value(file.buffer.asByteData());
await (FontLoader('MyFont')..addFont(bytes)).load();
});
testWidgets('Golden typography test', (WidgetTester tester) async {
await tester.pumpWidget(widget);
await expectLater(
find.byType(MaterialApp), matchesGoldenFile('goldens/typography.png'));
});
}
extension StylingExtensions on TextStyle {
TextStyle trimFontPackage() {
return TextStyle(
inherit: inherit,
color: color,
backgroundColor: backgroundColor,
fontSize: fontSize,
fontWeight: fontWeight,
fontStyle: fontStyle,
letterSpacing: letterSpacing,
wordSpacing: wordSpacing,
textBaseline: textBaseline,
height: height,
locale: locale,
foreground: foreground,
background: background,
shadows: shadows,
fontFeatures: fontFeatures,
decoration: decoration,
decorationColor: decorationColor,
decorationStyle: decorationStyle,
decorationThickness: decorationThickness,
debugLabel: debugLabel,
/// `replaceAll` only required if loading multiple fonts,
/// otherwise set value to your single `fontFamily` name
fontFamily: fontFamily.replaceAll('packages/<package_name>/', ''),
);
}
}
或者如果像我一样,自定义图标也有同样的问题,同样可以在您的自定义 IconData
黄金测试中使用类似的扩展方法来完成,删除 fontPackage
值:
extension IconExtensions on IconData {
IconData convertToGolden() => IconData(
this.codePoint,
fontFamily: this.fontFamily,
);
}
您的应用端
pubspec.yaml
# ...
dependencies:
flutter:
sdk: flutter
<package_name>:
git:
url: <url_to_hosted_package>.git
ref: <release_tag>
main.dart
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData.light().copyWith(
textTheme: TextTheme(
headline1: BrandStyles.headline1Style,
),
),
);
}
}
现在不再需要在您的应用程序中声明您的字体 pubspec.yaml
,甚至不需要在与您的实施应用程序相同的 project/repository 中拥有样式包。