如何在 Flutter 中测试渲染对象的内在大小

Posted

技术标签:

【中文标题】如何在 Flutter 中测试渲染对象的内在大小【英文标题】:How to test the intrinsic size of a render object in Flutter 【发布时间】:2020-03-22 17:25:17 【问题描述】:

我之前问过testing the size of a widget in Flutter。

但是,现在我正在尝试测试底层渲染对象的内在大小。

我试过这样做

testWidgets('MongolRichText has correct min instrinsic width',
    (WidgetTester tester) async 
  const String myString = 'A string';
  await tester.pumpWidget(
    Center(child: MongolText(myString)),
  );

  MongolRenderParagraph text = tester.firstRenderObject(find.byType(MongolRenderParagraph));
  expect(text, isNotNull);
  expect(text.getMinIntrinsicHeight(double.infinity), 100);
);

MongolText 在哪里创建 MongolRenderParagraph(类似于 Text 最终创建 Paragraph 的方式)。但是,我收到以下错误:

══╡ FLUTTER 测试框架发现异常╞════════════ 运行测试时引发以下 StateError: 不良状态:无元素

如何让底层渲染对象对其运行测试?

我找到了答案,所以我将其添加为自我回答问答。我的答案如下。

【问题讨论】:

【参考方案1】:

你可以直接创建渲染对象,所以你不需要抽小部件。

这里有一个简单的例子:

testWidgets('MongolRichText has correct min instrinsic width', (WidgetTester tester) async 
  MongolRenderParagraph paragraph = MongolRenderParagraph(TextSpan(text: 'A string'));
  final double textWidth = paragraph.getMaxIntrinsicWidth(double.infinity);
  expect(textWidth, greaterThan(0));
);

我通过查看 Flutter source code for paragraph_intrinsics_test.dart 找到了解决方案:

// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/rendering.dart';
import '../flutter_test_alternative.dart';

void main() 
  test('list body and paragraph intrinsics', () 
    final RenderParagraph paragraph = RenderParagraph(
      const TextSpan(
        style: TextStyle(height: 1.0),
        text: 'Hello World',
      ),
      textDirection: TextDirection.ltr,
    );
    final RenderListBody testBlock = RenderListBody(
      children: <RenderBox>[
        paragraph,
      ],
    );

    final double textWidth = paragraph.getMaxIntrinsicWidth(double.infinity);
    final double oneLineTextHeight = paragraph.getMinIntrinsicHeight(double.infinity);
    final double constrainedWidth = textWidth * 0.9;
    final double wrappedTextWidth = paragraph.getMinIntrinsicWidth(double.infinity);
    final double twoLinesTextHeight = paragraph.getMinIntrinsicHeight(constrainedWidth);
    final double manyLinesTextHeight = paragraph.getMinIntrinsicHeight(0.0);

    // paragraph
    expect(wrappedTextWidth, greaterThan(0.0));
    expect(wrappedTextWidth, lessThan(textWidth));
    expect(oneLineTextHeight, lessThan(twoLinesTextHeight));
    expect(twoLinesTextHeight, lessThan(oneLineTextHeight * 3.0));
    expect(manyLinesTextHeight, greaterThan(twoLinesTextHeight));
    expect(paragraph.getMaxIntrinsicHeight(double.infinity), equals(oneLineTextHeight));
    expect(paragraph.getMaxIntrinsicHeight(constrainedWidth), equals(twoLinesTextHeight));
    expect(paragraph.getMaxIntrinsicHeight(0.0), equals(manyLinesTextHeight));

    // vertical block (same expectations)
    expect(testBlock.getMinIntrinsicWidth(double.infinity), equals(wrappedTextWidth));
    expect(testBlock.getMaxIntrinsicWidth(double.infinity), equals(textWidth));
    expect(testBlock.getMinIntrinsicHeight(double.infinity), equals(oneLineTextHeight));
    expect(testBlock.getMinIntrinsicHeight(constrainedWidth), equals(twoLinesTextHeight));
    expect(testBlock.getMaxIntrinsicHeight(double.infinity), equals(oneLineTextHeight));
    expect(testBlock.getMaxIntrinsicHeight(constrainedWidth), equals(twoLinesTextHeight));
    expect(testBlock.getMinIntrinsicWidth(0.0), equals(wrappedTextWidth));
    expect(testBlock.getMaxIntrinsicWidth(0.0), equals(textWidth));
    expect(testBlock.getMinIntrinsicHeight(wrappedTextWidth), equals(twoLinesTextHeight));
    expect(testBlock.getMaxIntrinsicHeight(wrappedTextWidth), equals(twoLinesTextHeight));
    expect(testBlock.getMinIntrinsicHeight(0.0), equals(manyLinesTextHeight));
    expect(testBlock.getMaxIntrinsicHeight(0.0), equals(manyLinesTextHeight));

    // horizontal block (same expectations again)
    testBlock.axisDirection = AxisDirection.right;
    expect(testBlock.getMinIntrinsicWidth(double.infinity), equals(wrappedTextWidth));
    expect(testBlock.getMaxIntrinsicWidth(double.infinity), equals(textWidth));
    expect(testBlock.getMinIntrinsicHeight(double.infinity), equals(oneLineTextHeight));
    expect(testBlock.getMinIntrinsicHeight(constrainedWidth), equals(twoLinesTextHeight));
    expect(testBlock.getMaxIntrinsicHeight(double.infinity), equals(oneLineTextHeight));
    expect(testBlock.getMaxIntrinsicHeight(constrainedWidth), equals(twoLinesTextHeight));
    expect(testBlock.getMinIntrinsicWidth(0.0), equals(wrappedTextWidth));
    expect(testBlock.getMaxIntrinsicWidth(0.0), equals(textWidth));
    expect(testBlock.getMinIntrinsicHeight(wrappedTextWidth), equals(twoLinesTextHeight));
    expect(testBlock.getMaxIntrinsicHeight(wrappedTextWidth), equals(twoLinesTextHeight));
    expect(testBlock.getMinIntrinsicHeight(0.0), equals(manyLinesTextHeight));
    expect(testBlock.getMaxIntrinsicHeight(0.0), equals(manyLinesTextHeight));
  );

【讨论】:

我仍然想知道为什么tester.firstRenderObject() 不起作用。

以上是关于如何在 Flutter 中测试渲染对象的内在大小的主要内容,如果未能解决你的问题,请参考以下文章

Flutter的布局

无法在列表视图构建器中测试没有大小的渲染框

颤振:布局期间对象被赋予无限大小

解决盒约束widget和assets里的加载资产技术在Flutter框架运用的方案Flutter高级技术

FLUTTER:如何在启动画面中更改图像的大小?

SVG 内容的内在大小属性