提供包时,自定义字体不会呈现为金色图像

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 中拥有样式包。