From 7490f1b1495f45d2e0cc258af61557db26ba2aec Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Wed, 5 Mar 2025 15:09:18 -0800 Subject: [PATCH 1/7] computeDryLayout should not access RenderBox.size --- .../lib/src/rendering/animated_size.dart | 8 ++-- packages/flutter/lib/src/rendering/box.dart | 20 ++++++++-- packages/flutter/test/rendering/box_test.dart | 39 +++++++++++++++++++ 3 files changed, 60 insertions(+), 7 deletions(-) diff --git a/packages/flutter/lib/src/rendering/animated_size.dart b/packages/flutter/lib/src/rendering/animated_size.dart index 2646b83257d57..114dd005ce0c2 100644 --- a/packages/flutter/lib/src/rendering/animated_size.dart +++ b/packages/flutter/lib/src/rendering/animated_size.dart @@ -242,6 +242,8 @@ class RenderAnimatedSize extends RenderAligningShiftedBox { return _sizeTween.evaluate(_animation); } + Size? _currentSize; + @override void performLayout() { _lastValue = _controller.value; @@ -249,7 +251,7 @@ class RenderAnimatedSize extends RenderAligningShiftedBox { final BoxConstraints constraints = this.constraints; if (child == null || constraints.isTight) { _controller.stop(); - size = _sizeTween.begin = _sizeTween.end = constraints.smallest; + size = _currentSize = _sizeTween.begin = _sizeTween.end = constraints.smallest; _state = RenderAnimatedSizeState.start; child?.layout(constraints); return; @@ -268,7 +270,7 @@ class RenderAnimatedSize extends RenderAligningShiftedBox { _layoutUnstable(); } - size = constraints.constrain(_animatedSize!); + size = _currentSize = constraints.constrain(_animatedSize!); alignChild(); if (size.width < _sizeTween.end!.width || size.height < _sizeTween.end!.height) { @@ -292,7 +294,7 @@ class RenderAnimatedSize extends RenderAligningShiftedBox { return constraints.constrain(childSize); case RenderAnimatedSizeState.stable: if (_sizeTween.end != childSize) { - return constraints.constrain(size); + return constraints.constrain(_currentSize!); } else if (_controller.value == _controller.upperBound) { return constraints.constrain(childSize); } diff --git a/packages/flutter/lib/src/rendering/box.dart b/packages/flutter/lib/src/rendering/box.dart index 08a9dc5ba9b81..669d80d5daed7 100644 --- a/packages/flutter/lib/src/rendering/box.dart +++ b/packages/flutter/lib/src/rendering/box.dart @@ -2262,7 +2262,6 @@ abstract class RenderBox extends RenderObject { !doingRegularLayout || debugDoingThisResize || debugDoingThisLayout || - _computingThisDryLayout || RenderObject.debugActiveLayout == parent && size._canBeUsedByParent; assert( sizeAccessAllowed, @@ -2273,16 +2272,29 @@ abstract class RenderBox extends RenderObject { 'trying to access a child\'s size, pass "parentUsesSize: true" to ' "that child's layout() in ${objectRuntimeType(this, 'RenderBox')}.performLayout.", ); + final RenderBox? renderBoxDoingDryLayout = + _computingThisDryLayout + ? this + : (parent is RenderBox && parent._computingThisDryLayout ? parent : null); + + assert( + renderBoxDoingDryLayout == null, + 'RenderBox.size accessed in ' + '${objectRuntimeType(renderBoxDoingDryLayout, 'RenderBox')}.computeDryLayout. ' + "The computeDryLayout method must not access the RenderBox's own size, or the size of its child, " + "because it's established in performLayout or performResize using different BoxConstraints.", + ); + final RenderBox? renderBoxDoingDryBaseline = _computingThisDryBaseline ? this : (parent is RenderBox && parent._computingThisDryBaseline ? parent : null); assert( renderBoxDoingDryBaseline == null, + 'RenderBox.size accessed in ' - '${objectRuntimeType(renderBoxDoingDryBaseline, 'RenderBox')}.computeDryBaseline.' - 'The computeDryBaseline method must not access ' - '${renderBoxDoingDryBaseline == this ? "the RenderBox's own size" : "the size of its child"},' + '${objectRuntimeType(renderBoxDoingDryBaseline, 'RenderBox')}.computeDryBaseline. ' + "The computeDryBaseline method must not access the RenderBox's own size, or the size of its child, " "because it's established in performLayout or performResize using different BoxConstraints.", ); assert(size == _size); diff --git a/packages/flutter/test/rendering/box_test.dart b/packages/flutter/test/rendering/box_test.dart index 25753ee9c0c33..b0e6e1e79b06b 100644 --- a/packages/flutter/test/rendering/box_test.dart +++ b/packages/flutter/test/rendering/box_test.dart @@ -48,6 +48,18 @@ class BadBaselineRenderBox extends RenderBox { } } +class InvalidSizeAccessInDryLayoutBox extends RenderBox { + @override + Size computeDryLayout(covariant BoxConstraints constraints) { + return constraints.constrain(hasSize ? size : Size.infinite); + } + + @override + void performLayout() { + size = getDryLayout(constraints); + } +} + void main() { TestRenderingFlutterBinding.ensureInitialized(); @@ -231,6 +243,33 @@ void main() { } }); + test('Invalid size access error message', () { + final InvalidSizeAccessInDryLayoutBox testBox = InvalidSizeAccessInDryLayoutBox(); + + late FlutterErrorDetails errorDetails; + final FlutterExceptionHandler? oldHandler = FlutterError.onError; + FlutterError.onError = (FlutterErrorDetails details) { + errorDetails = details; + }; + try { + testBox.layout(const BoxConstraints.tightFor(width: 100.0, height: 100.0)); + } finally { + FlutterError.onError = oldHandler; + } + + expect( + errorDetails.toString().replaceAll('\n', ' '), + startsWith( + '══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞══════════════════════ ' + 'The following assertion was thrown during performLayout(): ' + 'RenderBox.size accessed in ' + 'InvalidSizeAccessInDryLayoutBox.computeDryLayout. ' + "The computeDryLayout method must not access the RenderBox's own size, or the size of its child, " + "because it's established in performLayout or performResize using different BoxConstraints.", + ), + ); + }); + test('Flex and padding', () { final RenderBox size = RenderConstrainedBox( additionalConstraints: const BoxConstraints().tighten(height: 100.0), From d9baaf20a6fcfc515ec2830c147ab00e61e9f244 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Wed, 5 Mar 2025 15:16:21 -0800 Subject: [PATCH 2/7] type check => null check --- .../flutter/lib/src/rendering/object.dart | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart index 5a085218b8165..c34108e85495b 100644 --- a/packages/flutter/lib/src/rendering/object.dart +++ b/packages/flutter/lib/src/rendering/object.dart @@ -2594,7 +2594,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge void scheduleInitialLayout() { assert(!_debugDisposed); assert(attached); - assert(parent is! RenderObject); + assert(parent == null); assert(!owner!._debugDoingLayout); assert(_relayoutBoundary == null); _relayoutBoundary = this; @@ -2712,7 +2712,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge assert(!_debugDoingThisResize); assert(!_debugDoingThisLayout); final bool isRelayoutBoundary = - !parentUsesSize || sizedByParent || constraints.isTight || parent is! RenderObject; + !parentUsesSize || sizedByParent || constraints.isTight || parent == null; final RenderObject relayoutBoundary = isRelayoutBoundary ? this : parent!._relayoutBoundary!; assert(() { _debugCanParentUseSize = parentUsesSize; @@ -3077,8 +3077,8 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge return; } _needsCompositingBitsUpdate = true; - if (parent is RenderObject) { - final RenderObject parent = this.parent!; + final RenderObject? parent = this.parent; + if (parent != null) { if (parent._needsCompositingBitsUpdate) { return; } @@ -3089,9 +3089,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge } } // parent is fine (or there isn't one), but we are dirty - if (owner != null) { - owner!._nodesNeedingCompositingBitsUpdate.add(this); - } + owner?._nodesNeedingCompositingBitsUpdate.add(this); } late bool _needsCompositing; // initialized in the constructor @@ -3299,7 +3297,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge assert(_layerHandle.layer != null); assert(!_layerHandle.layer!.attached); RenderObject? node = parent; - while (node is RenderObject) { + while (node != null) { if (node.isRepaintBoundary) { if (node._layerHandle.layer == null) { // Looks like the subtree here has never been painted. Let it handle itself. @@ -3324,7 +3322,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge void scheduleInitialPaint(ContainerLayer rootLayer) { assert(rootLayer.attached); assert(attached); - assert(parent is! RenderObject); + assert(parent == null); assert(!owner!._debugDoingPaint); assert(isRepaintBoundary); assert(_layerHandle.layer == null); @@ -3342,7 +3340,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge assert(!_debugDisposed); assert(rootLayer.attached); assert(attached); - assert(parent is! RenderObject); + assert(parent == null); assert(!owner!._debugDoingPaint); assert(isRepaintBoundary); assert(_layerHandle.layer != null); // use scheduleInitialPaint the first time @@ -3391,8 +3389,8 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge } assert(() { if (_needsCompositingBitsUpdate) { - if (parent is RenderObject) { - final RenderObject parent = this.parent!; + final RenderObject? parent = this.parent; + if (parent != null) { bool visitedByParent = false; parent.visitChildren((RenderObject child) { if (child == this) { @@ -3669,7 +3667,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge void scheduleInitialSemantics() { assert(!_debugDisposed); assert(attached); - assert(parent is! RenderObject); + assert(parent == null); assert(!owner!._debugDoingSemantics); assert(_semantics.parentDataDirty || !_semantics.built); assert(owner!._semanticsOwner != null); @@ -4005,14 +4003,12 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge Duration duration = Duration.zero, Curve curve = Curves.ease, }) { - if (parent is RenderObject) { - parent!.showOnScreen( - descendant: descendant ?? this, - rect: rect, - duration: duration, - curve: curve, - ); - } + parent?.showOnScreen( + descendant: descendant ?? this, + rect: rect, + duration: duration, + curve: curve, + ); } /// Adds a debug representation of a [RenderObject] optimized for including in From bbc570045253c3cba3801e04451b5c119b2723d7 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Wed, 5 Mar 2025 16:04:07 -0800 Subject: [PATCH 3/7] analyzer --- packages/flutter/lib/src/rendering/animated_size.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/rendering/animated_size.dart b/packages/flutter/lib/src/rendering/animated_size.dart index 114dd005ce0c2..2dbb2da17d7ba 100644 --- a/packages/flutter/lib/src/rendering/animated_size.dart +++ b/packages/flutter/lib/src/rendering/animated_size.dart @@ -242,7 +242,7 @@ class RenderAnimatedSize extends RenderAligningShiftedBox { return _sizeTween.evaluate(_animation); } - Size? _currentSize; + late Size _currentSize; @override void performLayout() { From 3245c23eae5d317844df9af047c610c21de899d7 Mon Sep 17 00:00:00 2001 From: LongCat is Looong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Thu, 6 Mar 2025 10:57:45 -0800 Subject: [PATCH 4/7] fix tests --- .../lib/src/rendering/animated_size.dart | 2 +- packages/flutter/lib/src/rendering/box.dart | 2 +- .../flutter/test/material/list_tile_test.dart | 117 +++++++++--------- 3 files changed, 58 insertions(+), 63 deletions(-) diff --git a/packages/flutter/lib/src/rendering/animated_size.dart b/packages/flutter/lib/src/rendering/animated_size.dart index 2dbb2da17d7ba..b41fb4568eaa5 100644 --- a/packages/flutter/lib/src/rendering/animated_size.dart +++ b/packages/flutter/lib/src/rendering/animated_size.dart @@ -294,7 +294,7 @@ class RenderAnimatedSize extends RenderAligningShiftedBox { return constraints.constrain(childSize); case RenderAnimatedSizeState.stable: if (_sizeTween.end != childSize) { - return constraints.constrain(_currentSize!); + return constraints.constrain(_currentSize); } else if (_controller.value == _controller.upperBound) { return constraints.constrain(childSize); } diff --git a/packages/flutter/lib/src/rendering/box.dart b/packages/flutter/lib/src/rendering/box.dart index 669d80d5daed7..eb57aba61d5e5 100644 --- a/packages/flutter/lib/src/rendering/box.dart +++ b/packages/flutter/lib/src/rendering/box.dart @@ -2752,7 +2752,7 @@ abstract class RenderBox extends RenderObject { } finally { RenderObject.debugCheckingIntrinsics = false; } - if (_debugDryLayoutCalculationValid && dryLayoutSize != size) { + if (_debugDryLayoutCalculationValid && dryLayoutSize != _size) { throw FlutterError.fromParts([ ErrorSummary( 'The size given to the ${objectRuntimeType(this, 'RenderBox')} class differs from the size computed by computeDryLayout.', diff --git a/packages/flutter/test/material/list_tile_test.dart b/packages/flutter/test/material/list_tile_test.dart index 1499bec968fd6..a3d414ec16f7a 100644 --- a/packages/flutter/test/material/list_tile_test.dart +++ b/packages/flutter/test/material/list_tile_test.dart @@ -2605,15 +2605,12 @@ void main() { expect(trailingOffset.dy - tileOffset.dy, topPosition); }); - testWidgets('Leading/Trailing exceeding list tile width throws exception', ( - WidgetTester tester, - ) async { - List exceptions = []; - FlutterExceptionHandler? oldHandler = FlutterError.onError; - FlutterError.onError = (FlutterErrorDetails details) { - exceptions.add(details.exception); - }; + group('Leading/Trailing exceeding list tile width throws exception', () { + final List exceptions = []; + final FlutterExceptionHandler? oldHandler = FlutterError.onError; + tearDown(exceptions.clear); + void onError(FlutterErrorDetails details) => exceptions.add(details.exception); Widget buildListTile({Widget? leading, Widget? trailing}) { return MaterialApp( home: Material( @@ -2624,61 +2621,59 @@ void main() { ); } - // Test a trailing widget that exceeds the list tile width. - // 16 (content padding) + 61 (leading width) + 24 (content padding) = 101. - // List tile width is 100 as a result, an exception should be thrown. - await tester.pumpWidget(buildListTile(leading: const SizedBox(width: 61))); + testWidgets('test 1', (WidgetTester tester) async { + // Test a trailing widget that exceeds the list tile width. + // 16 (content padding) + 61 (leading width) + 24 (content padding) = 101. + // List tile width is 100 as a result, an exception should be thrown. + FlutterError.onError = onError; + await tester.pumpWidget(buildListTile(leading: const SizedBox(width: 61))); + FlutterError.onError = oldHandler; - FlutterError.onError = oldHandler; - expect(exceptions.first.runtimeType, FlutterError); - FlutterError error = exceptions.first as FlutterError; - expect(error.diagnostics.length, 3); - expect( - error.diagnostics[0].toStringDeep(), - 'Leading widget consumes the entire tile width (including\nListTile.contentPadding).\n', - ); - expect( - error.diagnostics[1].toStringDeep(), - 'Either resize the tile width so that the leading widget plus any\n' - 'content padding do not exceed the tile width, or use a sized\n' - 'widget, or consider replacing ListTile with a custom widget.\n', - ); - expect( - error.diagnostics[2].toStringDeep(), - 'See also:\n' - 'https://api.flutter.dev/flutter/material/ListTile-class.html#material.ListTile.4\n', - ); + final FlutterError error = exceptions.first as FlutterError; + expect(error.diagnostics.length, 3); + expect( + error.diagnostics[0].toStringDeep(), + 'Leading widget consumes the entire tile width (including\nListTile.contentPadding).\n', + ); + expect( + error.diagnostics[1].toStringDeep(), + 'Either resize the tile width so that the leading widget plus any\n' + 'content padding do not exceed the tile width, or use a sized\n' + 'widget, or consider replacing ListTile with a custom widget.\n', + ); + expect( + error.diagnostics[2].toStringDeep(), + 'See also:\n' + 'https://api.flutter.dev/flutter/material/ListTile-class.html#material.ListTile.4\n', + ); + }); - exceptions = []; - oldHandler = FlutterError.onError; - FlutterError.onError = (FlutterErrorDetails details) { - exceptions.add(details.exception); - }; - - // Test a trailing widget that exceeds the list tile width. - // 16 (content padding) + 61 (trailing width) + 24 (content padding) = 101. - // List tile width is 100 as a result, an exception should be thrown. - await tester.pumpWidget(buildListTile(trailing: const SizedBox(width: 61))); - - FlutterError.onError = oldHandler; - expect(exceptions.first.runtimeType, FlutterError); - error = exceptions.first as FlutterError; - expect(error.diagnostics.length, 3); - expect( - error.diagnostics[0].toStringDeep(), - 'Trailing widget consumes the entire tile width (including\nListTile.contentPadding).\n', - ); - expect( - error.diagnostics[1].toStringDeep(), - 'Either resize the tile width so that the trailing widget plus any\n' - 'content padding do not exceed the tile width, or use a sized\n' - 'widget, or consider replacing ListTile with a custom widget.\n', - ); - expect( - error.diagnostics[2].toStringDeep(), - 'See also:\n' - 'https://api.flutter.dev/flutter/material/ListTile-class.html#material.ListTile.4\n', - ); + testWidgets('test 2', (WidgetTester tester) async { + // Test a trailing widget that exceeds the list tile width. + // 16 (content padding) + 61 (trailing width) + 24 (content padding) = 101. + // List tile width is 100 as a result, an exception should be thrown. + FlutterError.onError = onError; + await tester.pumpWidget(buildListTile(trailing: const SizedBox(width: 61))); + FlutterError.onError = oldHandler; + + final FlutterError error = exceptions.first as FlutterError; + expect(error.diagnostics.length, 3); + expect( + error.diagnostics[0].toStringDeep(), + 'Trailing widget consumes the entire tile width (including\nListTile.contentPadding).\n', + ); + expect( + error.diagnostics[1].toStringDeep(), + 'Either resize the tile width so that the trailing widget plus any\n' + 'content padding do not exceed the tile width, or use a sized\n' + 'widget, or consider replacing ListTile with a custom widget.\n', + ); + expect( + error.diagnostics[2].toStringDeep(), + 'See also:\n' + 'https://api.flutter.dev/flutter/material/ListTile-class.html#material.ListTile.4\n', + ); + }); }); group('Material 2', () { From f14125d6f515c7ee79b587ad4c2814b12fbea1df Mon Sep 17 00:00:00 2001 From: LongCat is Looong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Thu, 6 Mar 2025 12:43:27 -0800 Subject: [PATCH 5/7] fix tests --- packages/flutter/test/rendering/box_test.dart | 4 +--- .../selectable_region_context_menu_test.dart | 13 +++++-------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/flutter/test/rendering/box_test.dart b/packages/flutter/test/rendering/box_test.dart index b0e6e1e79b06b..54ceab3463f94 100644 --- a/packages/flutter/test/rendering/box_test.dart +++ b/packages/flutter/test/rendering/box_test.dart @@ -259,9 +259,7 @@ void main() { expect( errorDetails.toString().replaceAll('\n', ' '), - startsWith( - '══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞══════════════════════ ' - 'The following assertion was thrown during performLayout(): ' + contains( 'RenderBox.size accessed in ' 'InvalidSizeAccessInDryLayoutBox.computeDryLayout. ' "The computeDryLayout method must not access the RenderBox's own size, or the size of its child, " diff --git a/packages/flutter/test/widgets/selectable_region_context_menu_test.dart b/packages/flutter/test/widgets/selectable_region_context_menu_test.dart index c9be2665d9849..05a54bfd5c585 100644 --- a/packages/flutter/test/widgets/selectable_region_context_menu_test.dart +++ b/packages/flutter/test/widgets/selectable_region_context_menu_test.dart @@ -186,21 +186,18 @@ class RenderSelectionSpy extends RenderProxyBox with Selectable, SelectionRegist final Set listeners = {}; List events = []; - @override - Size get size => _size; - Size _size = Size.zero; - @override List get boundingBoxes => _boundingBoxes; final List _boundingBoxes = []; @override - Size computeDryLayout(BoxConstraints constraints) { - _size = Size(constraints.maxWidth, constraints.maxHeight); - _boundingBoxes.add(Rect.fromLTWH(0.0, 0.0, constraints.maxWidth, constraints.maxHeight)); - return _size; + void performLayout() { + _boundingBoxes.add(Offset.zero & (size = computeDryLayout(constraints))); } + @override + Size computeDryLayout(BoxConstraints constraints) => constraints.biggest; + @override void addListener(VoidCallback listener) => listeners.add(listener); From 02abe0797f6f3d49630f4e4ce677bd952956dedd Mon Sep 17 00:00:00 2001 From: LongCat is Looong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Thu, 6 Mar 2025 13:33:20 -0800 Subject: [PATCH 6/7] tests --- .../flutter/test/widgets/selectable_region_test.dart | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/flutter/test/widgets/selectable_region_test.dart b/packages/flutter/test/widgets/selectable_region_test.dart index f05d5dafa9281..2e4b6f6d8eaee 100644 --- a/packages/flutter/test/widgets/selectable_region_test.dart +++ b/packages/flutter/test/widgets/selectable_region_test.dart @@ -6359,17 +6359,13 @@ class RenderSelectionSpy extends RenderProxyBox with Selectable, SelectionRegist List events = []; @override - Size get size => _size; - Size _size = Size.zero; + List get boundingBoxes => [paintBounds]; @override - List get boundingBoxes => [paintBounds]; + Size computeDryLayout(BoxConstraints constraints) => constraints.biggest; @override - Size computeDryLayout(BoxConstraints constraints) { - _size = Size(constraints.maxWidth, constraints.maxHeight); - return _size; - } + void performLayout() => size = computeDryLayout(constraints); @override void addListener(VoidCallback listener) => listeners.add(listener); From b9493c5effec00cb3cdfd9a77f20d577c1709d57 Mon Sep 17 00:00:00 2001 From: LongCat is Looong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Fri, 7 Mar 2025 10:05:29 -0800 Subject: [PATCH 7/7] test names --- packages/flutter/test/material/list_tile_test.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/flutter/test/material/list_tile_test.dart b/packages/flutter/test/material/list_tile_test.dart index a3d414ec16f7a..ddcf420e81c84 100644 --- a/packages/flutter/test/material/list_tile_test.dart +++ b/packages/flutter/test/material/list_tile_test.dart @@ -2621,8 +2621,8 @@ void main() { ); } - testWidgets('test 1', (WidgetTester tester) async { - // Test a trailing widget that exceeds the list tile width. + testWidgets('leading', (WidgetTester tester) async { + // Test a leading widget that exceeds the list tile width. // 16 (content padding) + 61 (leading width) + 24 (content padding) = 101. // List tile width is 100 as a result, an exception should be thrown. FlutterError.onError = onError; @@ -2648,7 +2648,7 @@ void main() { ); }); - testWidgets('test 2', (WidgetTester tester) async { + testWidgets('trailing', (WidgetTester tester) async { // Test a trailing widget that exceeds the list tile width. // 16 (content padding) + 61 (trailing width) + 24 (content padding) = 101. // List tile width is 100 as a result, an exception should be thrown. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy