flutter TextPainter:painter.size different in Android vs.单元测试

hvvq6cgz  于 2023-05-23  发布在  Flutter
关注(0)|答案(1)|浏览(115)

我正在开发一个做布局的应用程序。并运行单元测试。
TextPainter为Android和单元测试返回不同的Size。Sp做Paragraph
即使在设备和单元测试中将fontFamily设置为Roboto-Black。(因为单元测试似乎不使用Roboto作为默认字体。
下面是计算字体大小的概述,有和没有Roboto-Black:

使用TextPainter对单词“test”的大小。

fontFamily: left empty, should be Roboto by default

Unit test: Size(400, 100) 
Android: Size(171, 117) ----------<< +1 width 
Chrome: Size(170, 117)

fontFamily: Roboto-Black

Unit test: Size(175, 120) ----------<< +3 height
Android: Size(175, 117)
Chrome: Size(175, 117)

使用段落的单词“test”的大小。

fontFamily: left empty, should be Roboto by default

Unit test: (200,200)
Android: (170.1, 117) -------<< + 0.2 width
Chrome: (169.9, 117)

fontFamily: Roboto-Black

Unit test: (174.31640625, 120) -------<< +3 height, +0.01640625 width
Android: (174.3, 117)
Chrome: (174.3, 117)
  • 注意:* 单元测试期望与174.31640625进行比较,表明结果未按应有的四舍五入?174.3未通过单元测试。
    设备段落
import 'dart:ui';

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: SafeArea(
        child: Scaffold(
          body: Builder(
            builder: ((context) {
              // ------------------------------------------------------

              const styleCustom =
                  TextStyle(fontFamily: 'myDefaultFont', fontSize: 100);
              const textCustom = Text('test', style: styleCustom);

              const style = TextStyle(fontSize: 100);
              const text = Text('test', style: style);

              // ------------------------------------------------------

              const constraints = ParagraphConstraints(width: 200);

              final builderCustom = ParagraphBuilder(ParagraphStyle(
                  fontFamily: styleCustom.fontFamily,
                  fontSize: styleCustom.fontSize));
              builderCustom.addText(textCustom.data!);
              final paragraphCustom = builderCustom.build();
              paragraphCustom.layout(constraints);
              final sizeCustom =
                  Size(paragraphCustom.longestLine, paragraphCustom.height);

              // ------------------------------------------------------

              final builder =
                  ParagraphBuilder(ParagraphStyle(fontSize: style.fontSize));
              builder.addText(text.data!);
              final paragraph = builder.build();
              paragraph.layout(constraints);
              final size = Size(paragraph.longestLine, paragraph.height);

              // ------------------------------------------------------

              // fontFamily: '',
              // Unit test: (200,200)
              // Android: (170.1, 117) -------<< + 0.2 width
              // Chrome: (169.9, 117)
              print(size);

              // fontFamily: 'myDefaultFont',
              // Unit test: (174.31640625, 120) -------<< +3 height, +0.01640625 width
              // Android: (174.3, 117)
              // Chrome: (174.3, 117)
              print(sizeCustom);

              return Column(
                children: [
                  text,
                  Text(size.toString()),
                  textCustom,
                  Text(sizeCustom.toString()),
                ],
              );
            }),
          ),
        ),
      ),
    );
  }
}

设备TextPainter

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: SafeArea(
        child: Scaffold(
          body: Builder(builder: ((context) {

            // myDefaultFont == Roboto-Black

            const styleCustom =
                TextStyle(fontFamily: 'myDefaultFont', fontSize: 100);
            const textCustom = Text('test', style: styleCustom);

            const style = TextStyle(fontSize: 100);
            const text = Text('test', style: style);

            // fontFamily: '',
            // Unit test: (400, 100) -------<<
            // Android: (171, 117) -------<<
            // Chrome: (170, 117)
            var painter = _getPainter(text, style);
            print(painter.size);

            // fontFamily: 'myDefaultFont',
            // Unit test: (175, 120) -------<<
            // Android: (175, 117)
            // Chrome: (175, 117)
            final painterCustom = _getPainter(textCustom, styleCustom);
            print(painterCustom.size);

            return Column(
              children: [
                text,
                Text(painter.size.toString()),
                textCustom,
                Text(painterCustom.size.toString()),
              ],
            );
          })),
        ),
      ),
    );
  }

  _getPainter(Text text, TextStyle style) {
    final TextPainter painter = TextPainter(
      text: TextSpan(children: [TextSpan(text: text.data!, style: style)]),
      textDirection: text.textDirection ?? TextDirection.ltr,
      maxLines: text.maxLines,
      textScaleFactor: text.textScaleFactor ?? 1.0,
      locale: text.locale,
      textAlign: text.textAlign ?? TextAlign.start,
      textHeightBehavior: text.textHeightBehavior,
      textWidthBasis: text.textWidthBasis ?? TextWidthBasis.parent,
    );

    painter.layout();
    return painter;
  }
}

单元测试

  • 注意:* 单元测试期望与174.31640625进行比较,表明结果未按应有的四舍五入?174.3未通过单元测试。
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();

  test('paragraph', () async {
    final Future<ByteData> data = rootBundle.load('assets/Roboto-Black.ttf');
    final FontLoader fontLoader = FontLoader('myDefaultFont')..addFont(data);
    await fontLoader.load();

    const styleCustom = TextStyle(fontFamily: 'myDefaultFont', fontSize: 100);
    const textCustom = Text('test', style: styleCustom);

    const style = TextStyle(fontSize: 100);
    const text = Text('test', style: style);

    // ------------------------------------------------------

    const constraints = ParagraphConstraints(width: 200);

    final builderCustom = ParagraphBuilder(ParagraphStyle(
        fontFamily: styleCustom.fontFamily, fontSize: styleCustom.fontSize));
    builderCustom.addText(textCustom.data!);
    final paragraphCustom = builderCustom.build();
    paragraphCustom.layout(constraints);
    final sizeCustom =
        Size(paragraphCustom.longestLine, paragraphCustom.height);

    // ------------------------------------------------------

    final builder = ParagraphBuilder(ParagraphStyle(fontSize: style.fontSize));
    builder.addText(text.data!);
    final paragraph = builder.build();
    paragraph.layout(constraints);
    final size = Size(paragraph.longestLine, paragraph.height);

    print(size);
    print(sizeCustom);

    expect(size, const Size(200, 200));
    expect(sizeCustom, const Size(174.31640625, 120));
  });

  test('textpainter', () async {
    final Future<ByteData> data = rootBundle.load('assets/Roboto-Black.ttf');
    final FontLoader fontLoader = FontLoader('myDefaultFont')..addFont(data);
    await fontLoader.load();

    const style = TextStyle(fontSize: 100);
    const text = Text('test', style: style);

    const styleCustom = TextStyle(fontFamily: 'myDefaultFont', fontSize: 100);
    const textCustom = Text('test', style: styleCustom);

    var painter = _getPainter(text, style);

    final painterCustom = _getPainter(textCustom, styleCustom);

    print(painter.size);
    print(painterCustom.size);

    expect(painter.size, const Size(400, 100));
    expect(painterCustom.size, const Size(175, 120));
  });
}

_getPainter(Text text, TextStyle style) {
  final TextPainter painter = TextPainter(
    text: TextSpan(children: [TextSpan(text: text.data!, style: style)]),
    textDirection: text.textDirection ?? TextDirection.ltr,
    maxLines: text.maxLines,
    textScaleFactor: text.textScaleFactor ?? 1.0,
    locale: text.locale,
    textAlign: text.textAlign ?? TextAlign.start,
    textHeightBehavior: text.textHeightBehavior,
    textWidthBasis: text.textWidthBasis ?? TextWidthBasis.parent,
  );

  painter.layout();
  return painter;
}

问题

需要更改哪些参数才能使器械和单元测试的尺寸相同?

yv5phkfx

yv5phkfx1#

结果表明,行高似乎是:

  • 1.2用于Flutter单元测试。
  • 1.17 for Flutter on(my)Android.

这解释了字体大小为100的Roboto的差异,它在Android上呈现的高度为117,但在单元测试中呈现的高度为120。
将行高设置为1.0将产生Size(175,100)

const style = TextStyle(
  fontFamily: 'Roboto',
  fontSize: 100,
  fontWeight: FontWeight.w400,
  textBaseline: TextBaseline.alphabetic,
  decoration: TextDecoration.none,
  height: 1.0,
);

const text = Text('test', style: style);
const constraints = BoxConstraints(maxHeight: 200);

final p = RenderParagraph(
  TextSpan(text: text.data!, style: style),
  textDirection: TextDirection.ltr,
);

p.layout(constraints);
final sizeCustom = p.size;

print(sizeCustom); // Size(175, 100)

目前,这似乎是Roboto在(我的)Android移动的上的默认样式:

const style = TextStyle(
      fontFamily: 'roboto',
      fontSize: 14, // 100
      fontWeight: FontWeight.w400,
      textBaseline: TextBaseline.alphabetic,
      decoration: TextDecoration.none,
      height: 1.17,
    );

const textCustom = Text('test', style: style);

相关问题