From 3437b7700729a44ce178abaccbf2143beaaac775 Mon Sep 17 00:00:00 2001 From: Adam Barth Date: Tue, 29 Aug 2017 20:34:06 -0700 Subject: [PATCH] Add support for RTL to Wrap (#11809) Fixes #11389 --- packages/flutter/lib/src/rendering/flex.dart | 4 +- packages/flutter/lib/src/rendering/wrap.dart | 195 +++++++++++- packages/flutter/lib/src/widgets/basic.dart | 85 ++++- packages/flutter/test/widgets/wrap_test.dart | 318 ++++++++++++++++++- 4 files changed, 579 insertions(+), 23 deletions(-) diff --git a/packages/flutter/lib/src/rendering/flex.dart b/packages/flutter/lib/src/rendering/flex.dart index 9d89645027..57c2e2d6e5 100644 --- a/packages/flutter/lib/src/rendering/flex.dart +++ b/packages/flutter/lib/src/rendering/flex.dart @@ -359,8 +359,8 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin _textDirection; + TextDirection _textDirection; + set textDirection(TextDirection value) { + if (_textDirection != value) { + _textDirection = value; + markNeedsLayout(); + } + } + + /// Determines the order to lay children out vertically and how to interpret + /// `start` and `end` in the vertical direction. + /// + /// If the [direction] is [Axis.vertical], this controls which order children + /// are painted in (down or up), the meaning of the [alignment] property's + /// [WrapAlignment.start] and [WrapAlignment.end] values. + /// + /// If the [direction] is [Axis.vertical], and either the [alignment] + /// is either [WrapAlignment.start] or [WrapAlignment.end], or there's + /// more than one child, then the [verticalDirection] must not be null. + /// + /// If the [direction] is [Axis.horizontal], this controls the order in which + /// runs are positioned, the meaning of the [runAlignment] property's + /// [WrapAlignment.start] and [WrapAlignment.end] values, as well as the + /// [crossAxisAlignment] property's [WrapCrossAlignment.start] and + /// [WrapCrossAlignment.end] values. + /// + /// If the [direction] is [Axis.horizontal], and either the + /// [runAlignment] is either [WrapAlignment.start] or [WrapAlignment.end], the + /// [crossAxisAlignment] is either [WrapCrossAlignment.start] or + /// [WrapCrossAlignment.end], or there's more than one child, then the + /// [verticalDirection] must not be null. + VerticalDirection get verticalDirection => _verticalDirection; + VerticalDirection _verticalDirection; + set verticalDirection(VerticalDirection value) { + if (_verticalDirection != value) { + _verticalDirection = value; + markNeedsLayout(); + } + } + + bool get _debugHasNecessaryDirections { + assert(direction != null); + assert(alignment != null); + assert(runAlignment != null); + assert(crossAxisAlignment != null); + if (firstChild != null && lastChild != firstChild) { + // i.e. there's more than one child + switch (direction) { + case Axis.horizontal: + assert(textDirection != null, 'Horizontal $runtimeType with multiple children has a null textDirection, so the layout order is undefined.'); + break; + case Axis.vertical: + assert(verticalDirection != null, 'Vertical $runtimeType with multiple children has a null verticalDirection, so the layout order is undefined.'); + break; + } + } + if (alignment == WrapAlignment.start || alignment == WrapAlignment.end) { + switch (direction) { + case Axis.horizontal: + assert(textDirection != null, 'Horizontal $runtimeType with alignment $alignment has a null textDirection, so the alignment cannot be resolved.'); + break; + case Axis.vertical: + assert(verticalDirection != null, 'Vertical $runtimeType with alignment $alignment has a null verticalDirection, so the alignment cannot be resolved.'); + break; + } + } + if (runAlignment == WrapAlignment.start || runAlignment == WrapAlignment.end) { + switch (direction) { + case Axis.horizontal: + assert(verticalDirection != null, 'Horizontal $runtimeType with runAlignment $runAlignment has a null verticalDirection, so the alignment cannot be resolved.'); + break; + case Axis.vertical: + assert(textDirection != null, 'Vertical $runtimeType with runAlignment $runAlignment has a null textDirection, so the alignment cannot be resolved.'); + break; + } + } + if (crossAxisAlignment == WrapCrossAlignment.start || crossAxisAlignment == WrapCrossAlignment.end) { + switch (direction) { + case Axis.horizontal: + assert(verticalDirection != null, 'Horizontal $runtimeType with crossAxisAlignment $crossAxisAlignment has a null verticalDirection, so the alignment cannot be resolved.'); + break; + case Axis.vertical: + assert(textDirection != null, 'Vertical $runtimeType with crossAxisAlignment $crossAxisAlignment has a null textDirection, so the alignment cannot be resolved.'); + break; + } + } + return true; + } + @override void setupParentData(RenderBox child) { if (child.parentData is! WrapParentData) @@ -408,14 +548,15 @@ class RenderWrap extends RenderBox with ContainerRenderObjectMixin runMetrics = <_RunMetrics>[]; double mainAxisExtent = 0.0; double crossAxisExtent = 0.0; @@ -526,7 +680,9 @@ class RenderWrap extends RenderBox with ContainerRenderObjectMixin('runAlignment', runAlignment)); description.add(new DoubleProperty('runSpacing', runSpacing)); description.add(new DoubleProperty('crossAxisAlignment', runSpacing)); + description.add(new EnumProperty('textDirection', textDirection, defaultValue: null)); + description.add(new EnumProperty('verticalDirection', verticalDirection, defaultValue: VerticalDirection.down)); } } diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index f1a98c2e72..29f3cf0de4 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -2740,9 +2740,9 @@ class Flex extends MultiChildRenderObjectWidget { /// /// Defaults to the ambient [Directionality]. /// - /// If the [direction] is [Axis.horizontal], this controls which order - /// children are painted in (left-to-right or right-to-left), and the meaning - /// of the [mainAxisAlignment] property's [MainAxisAlignment.start] and + /// If the [direction] is [Axis.horizontal], this controls the order in which + /// the children are positioned (left-to-right or right-to-left), and the + /// meaning of the [mainAxisAlignment] property's [MainAxisAlignment.start] and /// [MainAxisAlignment.end] values. /// /// If the [direction] is [Axis.horizontal], and either the @@ -3321,6 +3321,12 @@ class Wrap extends MultiChildRenderObjectWidget { /// /// By default, the wrap layout is horizontal and both the children and the /// runs are aligned to the start. + /// + /// The [textDirection] argument defaults to the ambient [Directionality], if + /// any. If there is no ambient directionality, and a text direction is going + /// to be necessary to decide which direction to lay the children in or to + /// disambiguate `start` or `end` values for the main or cross axis + /// directions, the [textDirection] must not be null. Wrap({ Key key, this.direction: Axis.horizontal, @@ -3329,6 +3335,8 @@ class Wrap extends MultiChildRenderObjectWidget { this.runAlignment: WrapAlignment.start, this.runSpacing: 0.0, this.crossAxisAlignment: WrapCrossAlignment.start, + this.textDirection, + this.verticalDirection: VerticalDirection.down, List children: const [], }) : super(key: key, children: children); @@ -3412,6 +3420,58 @@ class Wrap extends MultiChildRenderObjectWidget { /// other in the cross axis. final WrapCrossAlignment crossAxisAlignment; + /// Determines the order to lay children out horizontally and how to interpret + /// `start` and `end` in the horizontal direction. + /// + /// Defaults to the ambient [Directionality]. + /// + /// If the [direction] is [Axis.horizontal], this controls order in which the + /// children are positioned (left-to-right or right-to-left), and the meaning + /// of the [alignment] property's [WrapAlignment.start] and + /// [WrapAlignment.end] values. + /// + /// If the [direction] is [Axis.horizontal], and either the + /// [alignment] is either [WrapAlignment.start] or [WrapAlignment.end], or + /// there's more than one child, then the [textDirection] (or the ambient + /// [Directionality]) must not be null. + /// + /// If the [direction] is [Axis.vertical], this controls the order in which + /// runs are positioned, the meaning of the [runAlignment] property's + /// [WrapAlignment.start] and [WrapAlignment.end] values, as well as the + /// [crossAxisAlignment] property's [WrapCrossAlignment.start] and + /// [WrapCrossAlignment.end] values. + /// + /// If the [direction] is [Axis.vertical], and either the + /// [runAlignment] is either [WrapAlignment.start] or [WrapAlignment.end], the + /// [crossAxisAlignment] is either [WrapCrossAlignment.start] or + /// [WrapCrossAlignment.end], or there's more than one child, then the + /// [textDirection] (or the ambient [Directionality]) must not be null. + final TextDirection textDirection; + + /// Determines the order to lay children out vertically and how to interpret + /// `start` and `end` in the vertical direction. + /// + /// If the [direction] is [Axis.vertical], this controls which order children + /// are painted in (down or up), the meaning of the [alignment] property's + /// [WrapAlignment.start] and [WrapAlignment.end] values. + /// + /// If the [direction] is [Axis.vertical], and either the [alignment] + /// is either [WrapAlignment.start] or [WrapAlignment.end], or there's + /// more than one child, then the [verticalDirection] must not be null. + /// + /// If the [direction] is [Axis.horizontal], this controls the order in which + /// runs are positioned, the meaning of the [runAlignment] property's + /// [WrapAlignment.start] and [WrapAlignment.end] values, as well as the + /// [crossAxisAlignment] property's [WrapCrossAlignment.start] and + /// [WrapCrossAlignment.end] values. + /// + /// If the [direction] is [Axis.horizontal], and either the + /// [runAlignment] is either [WrapAlignment.start] or [WrapAlignment.end], the + /// [crossAxisAlignment] is either [WrapCrossAlignment.start] or + /// [WrapCrossAlignment.end], or there's more than one child, then the + /// [verticalDirection] must not be null. + final VerticalDirection verticalDirection; + @override RenderWrap createRenderObject(BuildContext context) { return new RenderWrap( @@ -3421,6 +3481,8 @@ class Wrap extends MultiChildRenderObjectWidget { runAlignment: runAlignment, runSpacing: runSpacing, crossAxisAlignment: crossAxisAlignment, + textDirection: textDirection ?? Directionality.of(context), + verticalDirection: verticalDirection, ); } @@ -3432,7 +3494,22 @@ class Wrap extends MultiChildRenderObjectWidget { ..spacing = spacing ..runAlignment = runAlignment ..runSpacing = runSpacing - ..crossAxisAlignment = crossAxisAlignment; + ..crossAxisAlignment = crossAxisAlignment + ..textDirection = textDirection ?? Directionality.of(context) + ..verticalDirection = verticalDirection; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder description) { + super.debugFillProperties(description); + description.add(new EnumProperty('direction', direction)); + description.add(new EnumProperty('alignment', alignment)); + description.add(new DoubleProperty('spacing', spacing)); + description.add(new EnumProperty('runAlignment', runAlignment)); + description.add(new DoubleProperty('runSpacing', runSpacing)); + description.add(new DoubleProperty('crossAxisAlignment', runSpacing)); + description.add(new EnumProperty('textDirection', textDirection, defaultValue: null)); + description.add(new EnumProperty('verticalDirection', verticalDirection, defaultValue: VerticalDirection.down)); } } diff --git a/packages/flutter/test/widgets/wrap_test.dart b/packages/flutter/test/widgets/wrap_test.dart index 4007b31f6e..9440522bb2 100644 --- a/packages/flutter/test/widgets/wrap_test.dart +++ b/packages/flutter/test/widgets/wrap_test.dart @@ -16,10 +16,11 @@ void verify(WidgetTester tester, List answerKey) { } void main() { - testWidgets('Basic Wrap test', (WidgetTester tester) async { + testWidgets('Basic Wrap test (LTR)', (WidgetTester tester) async { await tester.pumpWidget( new Wrap( alignment: WrapAlignment.start, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 300.0, height: 100.0), const SizedBox(width: 300.0, height: 100.0), @@ -38,6 +39,7 @@ void main() { await tester.pumpWidget( new Wrap( alignment: WrapAlignment.center, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 300.0, height: 100.0), const SizedBox(width: 300.0, height: 100.0), @@ -56,6 +58,7 @@ void main() { await tester.pumpWidget( new Wrap( alignment: WrapAlignment.end, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 300.0, height: 100.0), const SizedBox(width: 300.0, height: 100.0), @@ -75,6 +78,7 @@ void main() { new Wrap( alignment: WrapAlignment.start, crossAxisAlignment: WrapCrossAlignment.start, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 300.0, height: 50.0), const SizedBox(width: 300.0, height: 100.0), @@ -94,6 +98,7 @@ void main() { new Wrap( alignment: WrapAlignment.start, crossAxisAlignment: WrapCrossAlignment.center, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 300.0, height: 50.0), const SizedBox(width: 300.0, height: 100.0), @@ -113,6 +118,7 @@ void main() { new Wrap( alignment: WrapAlignment.start, crossAxisAlignment: WrapCrossAlignment.end, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 300.0, height: 50.0), const SizedBox(width: 300.0, height: 100.0), @@ -130,15 +136,139 @@ void main() { }); + testWidgets('Basic Wrap test (RTL)', (WidgetTester tester) async { + await tester.pumpWidget( + new Wrap( + alignment: WrapAlignment.start, + textDirection: TextDirection.rtl, + children: [ + const SizedBox(width: 300.0, height: 100.0), + const SizedBox(width: 300.0, height: 100.0), + const SizedBox(width: 300.0, height: 100.0), + const SizedBox(width: 300.0, height: 100.0), + ], + ), + ); + verify(tester, [ + const Offset(500.0, 0.0), + const Offset(200.0, 0.0), + const Offset(500.0, 100.0), + const Offset(200.0, 100.0), + ]); + + await tester.pumpWidget( + new Wrap( + alignment: WrapAlignment.center, + textDirection: TextDirection.rtl, + children: [ + const SizedBox(width: 300.0, height: 100.0), + const SizedBox(width: 300.0, height: 100.0), + const SizedBox(width: 300.0, height: 100.0), + const SizedBox(width: 300.0, height: 100.0), + ], + ), + ); + verify(tester, [ + const Offset(400.0, 0.0), + const Offset(100.0, 0.0), + const Offset(400.0, 100.0), + const Offset(100.0, 100.0), + ]); + + await tester.pumpWidget( + new Wrap( + alignment: WrapAlignment.end, + textDirection: TextDirection.rtl, + children: [ + const SizedBox(width: 300.0, height: 100.0), + const SizedBox(width: 300.0, height: 100.0), + const SizedBox(width: 300.0, height: 100.0), + const SizedBox(width: 300.0, height: 100.0), + ], + ), + ); + verify(tester, [ + const Offset(300.0, 0.0), + const Offset(0.0, 0.0), + const Offset(300.0, 100.0), + const Offset(0.0, 100.0), + ]); + + await tester.pumpWidget( + new Wrap( + alignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.start, + textDirection: TextDirection.ltr, + verticalDirection: VerticalDirection.up, + children: [ + const SizedBox(width: 300.0, height: 50.0), + const SizedBox(width: 300.0, height: 100.0), + const SizedBox(width: 300.0, height: 100.0), + const SizedBox(width: 300.0, height: 50.0), + ], + ), + ); + verify(tester, [ + const Offset(0.0, 550.0), + const Offset(300.0, 500.0), + const Offset(0.0, 400.0), + const Offset(300.0, 450.0), + ]); + + await tester.pumpWidget( + new Wrap( + alignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.center, + textDirection: TextDirection.ltr, + verticalDirection: VerticalDirection.up, + children: [ + const SizedBox(width: 300.0, height: 50.0), + const SizedBox(width: 300.0, height: 100.0), + const SizedBox(width: 300.0, height: 100.0), + const SizedBox(width: 300.0, height: 50.0), + ], + ), + ); + verify(tester, [ + const Offset(0.0, 525.0), + const Offset(300.0, 500.0), + const Offset(0.0, 400.0), + const Offset(300.0, 425.0), + ]); + + await tester.pumpWidget( + new Wrap( + alignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.end, + textDirection: TextDirection.ltr, + verticalDirection: VerticalDirection.up, + children: [ + const SizedBox(width: 300.0, height: 50.0), + const SizedBox(width: 300.0, height: 100.0), + const SizedBox(width: 300.0, height: 100.0), + const SizedBox(width: 300.0, height: 50.0), + ], + ), + ); + verify(tester, [ + const Offset(0.0, 500.0), + const Offset(300.0, 500.0), + const Offset(0.0, 400.0), + const Offset(300.0, 400.0), + ]); + + }); + testWidgets('Empty wrap', (WidgetTester tester) async { - await tester.pumpWidget(new Center(child: new Wrap())); + await tester.pumpWidget(new Center(child: new Wrap(alignment: WrapAlignment.center))); expect(tester.renderObject(find.byType(Wrap)).size, equals(Size.zero)); }); - testWidgets('Wrap alignment', (WidgetTester tester) async { + testWidgets('Wrap alignment (LTR)', (WidgetTester tester) async { await tester.pumpWidget(new Wrap( alignment: WrapAlignment.center, spacing: 5.0, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 100.0, height: 10.0), const SizedBox(width: 200.0, height: 20.0), @@ -155,6 +285,7 @@ void main() { await tester.pumpWidget(new Wrap( alignment: WrapAlignment.spaceBetween, spacing: 5.0, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 100.0, height: 10.0), const SizedBox(width: 200.0, height: 20.0), @@ -171,6 +302,7 @@ void main() { await tester.pumpWidget(new Wrap( alignment: WrapAlignment.spaceAround, spacing: 5.0, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 100.0, height: 10.0), const SizedBox(width: 200.0, height: 20.0), @@ -187,6 +319,7 @@ void main() { await tester.pumpWidget(new Wrap( alignment: WrapAlignment.spaceEvenly, spacing: 5.0, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 100.0, height: 10.0), const SizedBox(width: 200.0, height: 20.0), @@ -201,10 +334,81 @@ void main() { ]); }); - testWidgets('Wrap runAlignment', (WidgetTester tester) async { + testWidgets('Wrap alignment (RTL)', (WidgetTester tester) async { + await tester.pumpWidget(new Wrap( + alignment: WrapAlignment.center, + spacing: 5.0, + textDirection: TextDirection.rtl, + children: [ + const SizedBox(width: 100.0, height: 10.0), + const SizedBox(width: 200.0, height: 20.0), + const SizedBox(width: 300.0, height: 30.0), + ], + )); + expect(tester.renderObject(find.byType(Wrap)).size, equals(const Size(800.0, 600.0))); + verify(tester, [ + const Offset(605.0, 0.0), + const Offset(400.0, 0.0), + const Offset(95.0, 0.0), + ]); + + await tester.pumpWidget(new Wrap( + alignment: WrapAlignment.spaceBetween, + spacing: 5.0, + textDirection: TextDirection.rtl, + children: [ + const SizedBox(width: 100.0, height: 10.0), + const SizedBox(width: 200.0, height: 20.0), + const SizedBox(width: 300.0, height: 30.0), + ], + )); + expect(tester.renderObject(find.byType(Wrap)).size, equals(const Size(800.0, 600.0))); + verify(tester, [ + const Offset(700.0, 0.0), + const Offset(400.0, 0.0), + const Offset(0.0, 0.0), + ]); + + await tester.pumpWidget(new Wrap( + alignment: WrapAlignment.spaceAround, + spacing: 5.0, + textDirection: TextDirection.rtl, + children: [ + const SizedBox(width: 100.0, height: 10.0), + const SizedBox(width: 200.0, height: 20.0), + const SizedBox(width: 310.0, height: 30.0), + ], + )); + expect(tester.renderObject(find.byType(Wrap)).size, equals(const Size(800.0, 600.0))); + verify(tester, [ + const Offset(670.0, 0.0), + const Offset(405.0, 0.0), + const Offset(30.0, 0.0), + ]); + + await tester.pumpWidget(new Wrap( + alignment: WrapAlignment.spaceEvenly, + spacing: 5.0, + textDirection: TextDirection.rtl, + children: [ + const SizedBox(width: 100.0, height: 10.0), + const SizedBox(width: 200.0, height: 20.0), + const SizedBox(width: 310.0, height: 30.0), + ], + )); + expect(tester.renderObject(find.byType(Wrap)).size, equals(const Size(800.0, 600.0))); + verify(tester, [ + const Offset(655.0, 0.0), + const Offset(405.0, 0.0), + const Offset(45.0, 0.0), + ]); + }); + + testWidgets('Wrap runAlignment (DOWN)', (WidgetTester tester) async { await tester.pumpWidget(new Wrap( runAlignment: WrapAlignment.center, runSpacing: 5.0, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 100.0, height: 10.0), const SizedBox(width: 200.0, height: 20.0), @@ -225,6 +429,7 @@ void main() { await tester.pumpWidget(new Wrap( runAlignment: WrapAlignment.spaceBetween, runSpacing: 5.0, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 100.0, height: 10.0), const SizedBox(width: 200.0, height: 20.0), @@ -245,6 +450,7 @@ void main() { await tester.pumpWidget(new Wrap( runAlignment: WrapAlignment.spaceAround, runSpacing: 5.0, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 100.0, height: 10.0), const SizedBox(width: 200.0, height: 20.0), @@ -265,6 +471,7 @@ void main() { await tester.pumpWidget(new Wrap( runAlignment: WrapAlignment.spaceEvenly, runSpacing: 5.0, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 100.0, height: 10.0), const SizedBox(width: 200.0, height: 20.0), @@ -284,6 +491,97 @@ void main() { }); + testWidgets('Wrap runAlignment (UP)', (WidgetTester tester) async { + await tester.pumpWidget(new Wrap( + runAlignment: WrapAlignment.center, + runSpacing: 5.0, + textDirection: TextDirection.ltr, + verticalDirection: VerticalDirection.up, + children: [ + const SizedBox(width: 100.0, height: 10.0), + const SizedBox(width: 200.0, height: 20.0), + const SizedBox(width: 300.0, height: 30.0), + const SizedBox(width: 400.0, height: 40.0), + const SizedBox(width: 500.0, height: 60.0), + ], + )); + expect(tester.renderObject(find.byType(Wrap)).size, equals(const Size(800.0, 600.0))); + verify(tester, [ + const Offset(0.0, 360.0), + const Offset(100.0, 350.0), + const Offset(300.0, 340.0), + const Offset(0.0, 295.0), + const Offset(0.0, 230.0), + ]); + + await tester.pumpWidget(new Wrap( + runAlignment: WrapAlignment.spaceBetween, + runSpacing: 5.0, + textDirection: TextDirection.ltr, + verticalDirection: VerticalDirection.up, + children: [ + const SizedBox(width: 100.0, height: 10.0), + const SizedBox(width: 200.0, height: 20.0), + const SizedBox(width: 300.0, height: 30.0), + const SizedBox(width: 400.0, height: 40.0), + const SizedBox(width: 500.0, height: 60.0), + ], + )); + expect(tester.renderObject(find.byType(Wrap)).size, equals(const Size(800.0, 600.0))); + verify(tester, [ + const Offset(0.0, 590.0), + const Offset(100.0, 580.0), + const Offset(300.0, 570.0), + const Offset(0.0, 295.0), + const Offset(0.0, 0.0), + ]); + + await tester.pumpWidget(new Wrap( + runAlignment: WrapAlignment.spaceAround, + runSpacing: 5.0, + textDirection: TextDirection.ltr, + verticalDirection: VerticalDirection.up, + children: [ + const SizedBox(width: 100.0, height: 10.0), + const SizedBox(width: 200.0, height: 20.0), + const SizedBox(width: 300.0, height: 30.0), + const SizedBox(width: 400.0, height: 40.0), + const SizedBox(width: 500.0, height: 70.0), + ], + )); + expect(tester.renderObject(find.byType(Wrap)).size, equals(const Size(800.0, 600.0))); + verify(tester, [ + const Offset(0.0, 515.0), + const Offset(100.0, 505.0), + const Offset(300.0, 495.0), + const Offset(0.0, 300.0), + const Offset(0.0, 75.0), + ]); + + await tester.pumpWidget(new Wrap( + runAlignment: WrapAlignment.spaceEvenly, + runSpacing: 5.0, + textDirection: TextDirection.ltr, + verticalDirection: VerticalDirection.up, + children: [ + const SizedBox(width: 100.0, height: 10.0), + const SizedBox(width: 200.0, height: 20.0), + const SizedBox(width: 300.0, height: 30.0), + const SizedBox(width: 400.0, height: 40.0), + const SizedBox(width: 500.0, height: 60.0), + ], + )); + expect(tester.renderObject(find.byType(Wrap)).size, equals(const Size(800.0, 600.0))); + verify(tester, [ + const Offset(0.0, 475.0), + const Offset(100.0, 465.0), + const Offset(300.0, 455.0), + const Offset(0.0, 295.0), + const Offset(0.0, 115.0), + ]); + + }); + testWidgets('Shrink-wrapping Wrap test', (WidgetTester tester) async { await tester.pumpWidget( new Align( @@ -291,6 +589,7 @@ void main() { child: new Wrap( alignment: WrapAlignment.end, crossAxisAlignment: WrapCrossAlignment.end, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 100.0, height: 10.0), const SizedBox(width: 200.0, height: 20.0), @@ -314,6 +613,7 @@ void main() { child: new Wrap( alignment: WrapAlignment.end, crossAxisAlignment: WrapCrossAlignment.end, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 400.0, height: 40.0), const SizedBox(width: 300.0, height: 30.0), @@ -340,6 +640,7 @@ void main() { runSpacing: 10.0, alignment: WrapAlignment.start, crossAxisAlignment: WrapCrossAlignment.start, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 500.0, height: 10.0), const SizedBox(width: 500.0, height: 20.0), @@ -368,6 +669,7 @@ void main() { runSpacing: 15.0, alignment: WrapAlignment.start, crossAxisAlignment: WrapCrossAlignment.start, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 10.0, height: 250.0), const SizedBox(width: 20.0, height: 250.0), @@ -396,6 +698,7 @@ void main() { direction: Axis.horizontal, spacing: 12.0, runSpacing: 8.0, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 10.0, height: 250.0), const SizedBox(width: 20.0, height: 250.0), @@ -420,6 +723,7 @@ void main() { testWidgets('Visual overflow generates a clip', (WidgetTester tester) async { await tester.pumpWidget(new Wrap( + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 500.0, height: 500.0), ], @@ -428,6 +732,7 @@ void main() { expect(tester.renderObject(find.byType(Wrap)), isNot(paints..clipRect())); await tester.pumpWidget(new Wrap( + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 500.0, height: 500.0), const SizedBox(width: 500.0, height: 500.0), @@ -443,6 +748,7 @@ void main() { await tester.pumpWidget(new Wrap( spacing: 10.0, runSpacing: 15.0, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 200.0, height: 300.0), const SizedBox(width: 200.0, height: 300.0), @@ -473,7 +779,7 @@ void main() { }); testWidgets('RenderWrap toStringShallow control test', (WidgetTester tester) async { - await tester.pumpWidget(new Wrap()); + await tester.pumpWidget(new Wrap(alignment: WrapAlignment.center)); final RenderBox wrap = tester.renderObject(find.byType(Wrap)); expect(wrap.toStringShallow(), hasOneLineDescription); @@ -483,6 +789,7 @@ void main() { await tester.pumpWidget(new Wrap( direction: Axis.vertical, runSpacing: 7.0, + textDirection: TextDirection.ltr, children: [ const SizedBox(width: 500.0, height: 400.0), const SizedBox(width: 500.0, height: 400.0), @@ -508,6 +815,7 @@ void main() { fontSize: 100.0, ), child: new Wrap( + textDirection: TextDirection.ltr, children: [ const Text('X'), ],