Commit 8eb6ad27 authored by Adam Barth's avatar Adam Barth Committed by GitHub

Add RTL support to GridView (#11921)

Fixes #11855
parent c896fe2f
...@@ -205,6 +205,7 @@ class _DayPickerGridDelegate extends SliverGridDelegate { ...@@ -205,6 +205,7 @@ class _DayPickerGridDelegate extends SliverGridDelegate {
crossAxisStride: tileWidth, crossAxisStride: tileWidth,
childMainAxisExtent: tileHeight, childMainAxisExtent: tileHeight,
childCrossAxisExtent: tileWidth, childCrossAxisExtent: tileWidth,
reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection),
); );
} }
......
...@@ -80,7 +80,7 @@ class ExpansionPanelList extends StatelessWidget { ...@@ -80,7 +80,7 @@ class ExpansionPanelList extends StatelessWidget {
assert(animationDuration != null), assert(animationDuration != null),
super(key: key); super(key: key);
/// The children of the expansion panel list. They are layed in a similar /// The children of the expansion panel list. They are laid out in a similar
/// fashion to [ListBody]. /// fashion to [ListBody].
final List<ExpansionPanel> children; final List<ExpansionPanel> children;
......
...@@ -49,15 +49,15 @@ class GridTile extends StatelessWidget { ...@@ -49,15 +49,15 @@ class GridTile extends StatelessWidget {
final List<Widget> children = <Widget>[ final List<Widget> children = <Widget>[
new Positioned.fill( new Positioned.fill(
child: child child: child,
) ),
]; ];
if (header != null) { if (header != null) {
children.add(new Positioned( children.add(new Positioned(
top: 0.0, top: 0.0,
left: 0.0, left: 0.0,
right: 0.0, right: 0.0,
child: header child: header,
)); ));
} }
if (footer != null) { if (footer != null) {
...@@ -65,7 +65,7 @@ class GridTile extends StatelessWidget { ...@@ -65,7 +65,7 @@ class GridTile extends StatelessWidget {
left: 0.0, left: 0.0,
bottom: 0.0, bottom: 0.0,
right: 0.0, right: 0.0,
child: footer child: footer,
)); ));
} }
return new Stack(children: children); return new Stack(children: children);
......
...@@ -89,6 +89,21 @@ Axis axisDirectionToAxis(AxisDirection axisDirection) { ...@@ -89,6 +89,21 @@ Axis axisDirectionToAxis(AxisDirection axisDirection) {
return null; return null;
} }
/// Returns the [AxisDirection] in which reading occurs in the given [TextDirection].
///
/// Specifically, returns [AxisDirection.left] for [TextDirection.rtl] and
/// [AxisDirection.right] for [TextDirection.ltr].
AxisDirection textDirectionToAxisDirection(TextDirection textDirection) {
assert(textDirection != null);
switch (textDirection) {
case TextDirection.rtl:
return AxisDirection.left;
case TextDirection.ltr:
return AxisDirection.right;
}
return null;
}
/// Returns the opposite of the given [AxisDirection]. /// Returns the opposite of the given [AxisDirection].
/// ///
/// Specifically, returns [AxisDirection.up] for [AxisDirection.down] (and /// Specifically, returns [AxisDirection.up] for [AxisDirection.down] (and
...@@ -192,6 +207,7 @@ class SliverConstraints extends Constraints { ...@@ -192,6 +207,7 @@ class SliverConstraints extends Constraints {
@required this.overlap, @required this.overlap,
@required this.remainingPaintExtent, @required this.remainingPaintExtent,
@required this.crossAxisExtent, @required this.crossAxisExtent,
@required this.crossAxisDirection,
@required this.viewportMainAxisExtent, @required this.viewportMainAxisExtent,
}) : assert(axisDirection != null), }) : assert(axisDirection != null),
assert(growthDirection != null), assert(growthDirection != null),
...@@ -200,6 +216,7 @@ class SliverConstraints extends Constraints { ...@@ -200,6 +216,7 @@ class SliverConstraints extends Constraints {
assert(overlap != null), assert(overlap != null),
assert(remainingPaintExtent != null), assert(remainingPaintExtent != null),
assert(crossAxisExtent != null), assert(crossAxisExtent != null),
assert(crossAxisDirection != null),
assert(viewportMainAxisExtent != null); assert(viewportMainAxisExtent != null);
/// Creates a copy of this object but with the given fields replaced with the /// Creates a copy of this object but with the given fields replaced with the
...@@ -212,6 +229,7 @@ class SliverConstraints extends Constraints { ...@@ -212,6 +229,7 @@ class SliverConstraints extends Constraints {
double overlap, double overlap,
double remainingPaintExtent, double remainingPaintExtent,
double crossAxisExtent, double crossAxisExtent,
AxisDirection crossAxisDirection,
double viewportMainAxisExtent, double viewportMainAxisExtent,
}) { }) {
return new SliverConstraints( return new SliverConstraints(
...@@ -222,6 +240,7 @@ class SliverConstraints extends Constraints { ...@@ -222,6 +240,7 @@ class SliverConstraints extends Constraints {
overlap: overlap ?? this.overlap, overlap: overlap ?? this.overlap,
remainingPaintExtent: remainingPaintExtent ?? this.remainingPaintExtent, remainingPaintExtent: remainingPaintExtent ?? this.remainingPaintExtent,
crossAxisExtent: crossAxisExtent ?? this.crossAxisExtent, crossAxisExtent: crossAxisExtent ?? this.crossAxisExtent,
crossAxisDirection: crossAxisDirection ?? this.crossAxisDirection,
viewportMainAxisExtent: viewportMainAxisExtent ?? this.viewportMainAxisExtent, viewportMainAxisExtent: viewportMainAxisExtent ?? this.viewportMainAxisExtent,
); );
} }
...@@ -315,9 +334,15 @@ class SliverConstraints extends Constraints { ...@@ -315,9 +334,15 @@ class SliverConstraints extends Constraints {
/// The number of pixels in the cross-axis. /// The number of pixels in the cross-axis.
/// ///
/// For a vertical list, this is the width of the sliver.. /// For a vertical list, this is the width of the sliver.
final double crossAxisExtent; final double crossAxisExtent;
/// The direction in which children should be placed in the cross axis.
///
/// Typically used in vertical lists to describe whether the ambient
/// [TextDirection] is [TextDirection.rtl] or [TextDirection.ltr].
final AxisDirection crossAxisDirection;
/// The number of pixels the viewport can display in the main axis. /// The number of pixels the viewport can display in the main axis.
/// ///
/// For a vertical list, this is the height of the viewport. /// For a vertical list, this is the height of the viewport.
...@@ -361,6 +386,7 @@ class SliverConstraints extends Constraints { ...@@ -361,6 +386,7 @@ class SliverConstraints extends Constraints {
bool get isNormalized { bool get isNormalized {
return scrollOffset >= 0.0 return scrollOffset >= 0.0
&& crossAxisExtent >= 0.0 && crossAxisExtent >= 0.0
&& axisDirectionToAxis(axisDirection) != axisDirectionToAxis(crossAxisDirection)
&& viewportMainAxisExtent >= 0.0 && viewportMainAxisExtent >= 0.0
&& remainingPaintExtent >= 0.0; && remainingPaintExtent >= 0.0;
} }
...@@ -421,6 +447,8 @@ class SliverConstraints extends Constraints { ...@@ -421,6 +447,8 @@ class SliverConstraints extends Constraints {
verify(viewportMainAxisExtent != null, 'The "viewportMainAxisExtent" is null.'); verify(viewportMainAxisExtent != null, 'The "viewportMainAxisExtent" is null.');
verify(scrollOffset >= 0.0, 'The "scrollOffset" is negative.'); verify(scrollOffset >= 0.0, 'The "scrollOffset" is negative.');
verify(crossAxisExtent >= 0.0, 'The "crossAxisExtent" is negative.'); verify(crossAxisExtent >= 0.0, 'The "crossAxisExtent" is negative.');
verify(crossAxisDirection != null, 'The "crossAxisDirection" is null.');
verify(axisDirectionToAxis(axisDirection) != axisDirectionToAxis(crossAxisDirection), 'The "axisDirection" and the "crossAxisDirection" are along the same axis.');
verify(viewportMainAxisExtent >= 0.0, 'The "viewportMainAxisExtent" is negative.'); verify(viewportMainAxisExtent >= 0.0, 'The "viewportMainAxisExtent" is negative.');
verify(remainingPaintExtent >= 0.0, 'The "remainingPaintExtent" is negative.'); verify(remainingPaintExtent >= 0.0, 'The "remainingPaintExtent" is negative.');
verify(isNormalized, 'The constraints are not normalized.'); // should be redundant with earlier checks verify(isNormalized, 'The constraints are not normalized.'); // should be redundant with earlier checks
...@@ -437,18 +465,28 @@ class SliverConstraints extends Constraints { ...@@ -437,18 +465,28 @@ class SliverConstraints extends Constraints {
return false; return false;
final SliverConstraints typedOther = other; final SliverConstraints typedOther = other;
assert(typedOther.debugAssertIsValid()); assert(typedOther.debugAssertIsValid());
return axisDirection == typedOther.axisDirection && return typedOther.axisDirection == axisDirection
growthDirection == typedOther.growthDirection && && typedOther.growthDirection == growthDirection
scrollOffset == typedOther.scrollOffset && && typedOther.scrollOffset == scrollOffset
overlap == typedOther.overlap && && typedOther.overlap == overlap
remainingPaintExtent == typedOther.remainingPaintExtent && && typedOther.remainingPaintExtent == remainingPaintExtent
crossAxisExtent == typedOther.crossAxisExtent && && typedOther.crossAxisExtent == crossAxisExtent
viewportMainAxisExtent == typedOther.viewportMainAxisExtent; && typedOther.crossAxisDirection == crossAxisDirection
&& typedOther.viewportMainAxisExtent == viewportMainAxisExtent;
} }
@override @override
int get hashCode { int get hashCode {
return hashValues(axisDirection, growthDirection, scrollOffset, overlap, remainingPaintExtent, crossAxisExtent, viewportMainAxisExtent); return hashValues(
axisDirection,
growthDirection,
scrollOffset,
overlap,
remainingPaintExtent,
crossAxisExtent,
crossAxisDirection,
viewportMainAxisExtent,
);
} }
@override @override
...@@ -461,6 +499,7 @@ class SliverConstraints extends Constraints { ...@@ -461,6 +499,7 @@ class SliverConstraints extends Constraints {
'remainingPaintExtent: ${remainingPaintExtent.toStringAsFixed(1)}, ' + 'remainingPaintExtent: ${remainingPaintExtent.toStringAsFixed(1)}, ' +
(overlap != 0.0 ? 'overlap: ${overlap.toStringAsFixed(1)}, ' : '') + (overlap != 0.0 ? 'overlap: ${overlap.toStringAsFixed(1)}, ' : '') +
'crossAxisExtent: ${crossAxisExtent.toStringAsFixed(1)}, ' + 'crossAxisExtent: ${crossAxisExtent.toStringAsFixed(1)}, ' +
'crossAxisDirection: $crossAxisDirection, ' +
'viewportMainAxisExtent: ${viewportMainAxisExtent.toStringAsFixed(1)}' + 'viewportMainAxisExtent: ${viewportMainAxisExtent.toStringAsFixed(1)}' +
')'; ')';
} }
......
...@@ -151,11 +151,13 @@ class SliverGridRegularTileLayout extends SliverGridLayout { ...@@ -151,11 +151,13 @@ class SliverGridRegularTileLayout extends SliverGridLayout {
@required this.crossAxisStride, @required this.crossAxisStride,
@required this.childMainAxisExtent, @required this.childMainAxisExtent,
@required this.childCrossAxisExtent, @required this.childCrossAxisExtent,
@required this.reverseCrossAxis,
}) : assert(crossAxisCount != null && crossAxisCount > 0), }) : assert(crossAxisCount != null && crossAxisCount > 0),
assert(mainAxisStride != null && mainAxisStride >= 0), assert(mainAxisStride != null && mainAxisStride >= 0),
assert(crossAxisStride != null && crossAxisStride >= 0), assert(crossAxisStride != null && crossAxisStride >= 0),
assert(childMainAxisExtent != null && childMainAxisExtent >= 0), assert(childMainAxisExtent != null && childMainAxisExtent >= 0),
assert(childCrossAxisExtent != null && childCrossAxisExtent >= 0); assert(childCrossAxisExtent != null && childCrossAxisExtent >= 0),
assert(reverseCrossAxis != null);
/// The number of children in the cross axis. /// The number of children in the cross axis.
final int crossAxisCount; final int crossAxisCount;
...@@ -176,6 +178,17 @@ class SliverGridRegularTileLayout extends SliverGridLayout { ...@@ -176,6 +178,17 @@ class SliverGridRegularTileLayout extends SliverGridLayout {
/// edge of the same tile in the cross axis. /// edge of the same tile in the cross axis.
final double childCrossAxisExtent; final double childCrossAxisExtent;
/// Whether the children should be placed in the opposite order of increasing
/// coordinates in the cross axis.
///
/// For example, if the cross axis is horizontal, the children are placed from
/// left to right when [reverseCrossAxis] is false and from right to left when
/// [reverseCrossAxis] is true.
///
/// Typically set to the return value of [axisDirectionIsReversed] applied to
/// the [SliverConstraints.crossAxisDirection].
final bool reverseCrossAxis;
@override @override
int getMinChildIndexForScrollOffset(double scrollOffset) { int getMinChildIndexForScrollOffset(double scrollOffset) {
return mainAxisStride > 0.0 ? crossAxisCount * (scrollOffset ~/ mainAxisStride) : 0; return mainAxisStride > 0.0 ? crossAxisCount * (scrollOffset ~/ mainAxisStride) : 0;
...@@ -190,11 +203,18 @@ class SliverGridRegularTileLayout extends SliverGridLayout { ...@@ -190,11 +203,18 @@ class SliverGridRegularTileLayout extends SliverGridLayout {
return 0; return 0;
} }
double _getOffsetFromStartInCrossAxis(double crossAxisStart) {
if (reverseCrossAxis)
return crossAxisCount * crossAxisStride - crossAxisStart - childCrossAxisExtent;
return crossAxisStart;
}
@override @override
SliverGridGeometry getGeometryForChildIndex(int index) { SliverGridGeometry getGeometryForChildIndex(int index) {
final double crossAxisStart = (index % crossAxisCount) * crossAxisStride;
return new SliverGridGeometry( return new SliverGridGeometry(
scrollOffset: (index ~/ crossAxisCount) * mainAxisStride, scrollOffset: (index ~/ crossAxisCount) * mainAxisStride,
crossAxisOffset: (index % crossAxisCount) * crossAxisStride, crossAxisOffset: _getOffsetFromStartInCrossAxis(crossAxisStart),
mainAxisExtent: childMainAxisExtent, mainAxisExtent: childMainAxisExtent,
crossAxisExtent: childCrossAxisExtent, crossAxisExtent: childCrossAxisExtent,
); );
...@@ -313,6 +333,7 @@ class SliverGridDelegateWithFixedCrossAxisCount extends SliverGridDelegate { ...@@ -313,6 +333,7 @@ class SliverGridDelegateWithFixedCrossAxisCount extends SliverGridDelegate {
crossAxisStride: childCrossAxisExtent + crossAxisSpacing, crossAxisStride: childCrossAxisExtent + crossAxisSpacing,
childMainAxisExtent: childMainAxisExtent, childMainAxisExtent: childMainAxisExtent,
childCrossAxisExtent: childCrossAxisExtent, childCrossAxisExtent: childCrossAxisExtent,
reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection),
); );
} }
...@@ -410,6 +431,7 @@ class SliverGridDelegateWithMaxCrossAxisExtent extends SliverGridDelegate { ...@@ -410,6 +431,7 @@ class SliverGridDelegateWithMaxCrossAxisExtent extends SliverGridDelegate {
crossAxisStride: childCrossAxisExtent + crossAxisSpacing, crossAxisStride: childCrossAxisExtent + crossAxisSpacing,
childMainAxisExtent: childMainAxisExtent, childMainAxisExtent: childMainAxisExtent,
childCrossAxisExtent: childCrossAxisExtent, childCrossAxisExtent: childCrossAxisExtent,
reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection),
); );
} }
......
...@@ -81,10 +81,14 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix ...@@ -81,10 +81,14 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
/// Initializes fields for subclasses. /// Initializes fields for subclasses.
RenderViewportBase({ RenderViewportBase({
AxisDirection axisDirection: AxisDirection.down, AxisDirection axisDirection: AxisDirection.down,
@required AxisDirection crossAxisDirection,
@required ViewportOffset offset, @required ViewportOffset offset,
}) : assert(axisDirection != null), }) : assert(axisDirection != null),
assert(crossAxisDirection != null),
assert(offset != null), assert(offset != null),
assert(axisDirectionToAxis(axisDirection) != axisDirectionToAxis(crossAxisDirection)),
_axisDirection = axisDirection, _axisDirection = axisDirection,
_crossAxisDirection = crossAxisDirection,
_offset = offset; _offset = offset;
@override @override
...@@ -118,6 +122,22 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix ...@@ -118,6 +122,22 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
markNeedsLayout(); markNeedsLayout();
} }
/// The direction in which child should be laid out in the cross axis.
///
/// For example, if the [axisDirection] is [AxisDirection.down], this property
/// is typically [AxisDirection.left] if the ambient [TextDirection] is
/// [TextDirection.rtl] and [AxisDirection.right] if the ambient
/// [TextDirection] is [TextDirection.ltr].
AxisDirection get crossAxisDirection => _crossAxisDirection;
AxisDirection _crossAxisDirection;
set crossAxisDirection(AxisDirection value) {
assert(value != null);
if (value == _crossAxisDirection)
return;
_crossAxisDirection = value;
markNeedsLayout();
}
/// The axis along which the viewport scrolls. /// The axis along which the viewport scrolls.
/// ///
/// For example, if the [axisDirection] is [AxisDirection.down], then the /// For example, if the [axisDirection] is [AxisDirection.down], then the
...@@ -271,6 +291,7 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix ...@@ -271,6 +291,7 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
overlap: maxPaintOffset - layoutOffset, overlap: maxPaintOffset - layoutOffset,
remainingPaintExtent: math.max(0.0, remainingPaintExtent - layoutOffset + initialLayoutOffset), remainingPaintExtent: math.max(0.0, remainingPaintExtent - layoutOffset + initialLayoutOffset),
crossAxisExtent: crossAxisExtent, crossAxisExtent: crossAxisExtent,
crossAxisDirection: crossAxisDirection,
viewportMainAxisExtent: mainAxisExtent, viewportMainAxisExtent: mainAxisExtent,
), parentUsesSize: true); ), parentUsesSize: true);
...@@ -507,6 +528,7 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix ...@@ -507,6 +528,7 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
void debugFillProperties(DiagnosticPropertiesBuilder description) { void debugFillProperties(DiagnosticPropertiesBuilder description) {
super.debugFillProperties(description); super.debugFillProperties(description);
description.add(new EnumProperty<AxisDirection>('axisDirection', axisDirection)); description.add(new EnumProperty<AxisDirection>('axisDirection', axisDirection));
description.add(new EnumProperty<AxisDirection>('crossAxisDirection', crossAxisDirection));
description.add(new DiagnosticsProperty<ViewportOffset>('offset', offset)); description.add(new DiagnosticsProperty<ViewportOffset>('offset', offset));
} }
...@@ -687,6 +709,7 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat ...@@ -687,6 +709,7 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat
/// [new ViewportOffset.zero] or [new ViewportOffset.fixed]. /// [new ViewportOffset.zero] or [new ViewportOffset.fixed].
RenderViewport({ RenderViewport({
AxisDirection axisDirection: AxisDirection.down, AxisDirection axisDirection: AxisDirection.down,
@required AxisDirection crossAxisDirection,
@required ViewportOffset offset, @required ViewportOffset offset,
double anchor: 0.0, double anchor: 0.0,
List<RenderSliver> children, List<RenderSliver> children,
...@@ -695,7 +718,7 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat ...@@ -695,7 +718,7 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat
assert(anchor >= 0.0 && anchor <= 1.0), assert(anchor >= 0.0 && anchor <= 1.0),
_anchor = anchor, _anchor = anchor,
_center = center, _center = center,
super(axisDirection: axisDirection, offset: offset) { super(axisDirection: axisDirection, crossAxisDirection: crossAxisDirection, offset: offset) {
addAll(children); addAll(children);
if (center == null && firstChild != null) if (center == null && firstChild != null)
_center = firstChild; _center = firstChild;
...@@ -1120,9 +1143,10 @@ class RenderShrinkWrappingViewport extends RenderViewportBase<SliverLogicalConta ...@@ -1120,9 +1143,10 @@ class RenderShrinkWrappingViewport extends RenderViewportBase<SliverLogicalConta
/// [new ViewportOffset.zero] or [new ViewportOffset.fixed]. /// [new ViewportOffset.zero] or [new ViewportOffset.fixed].
RenderShrinkWrappingViewport({ RenderShrinkWrappingViewport({
AxisDirection axisDirection: AxisDirection.down, AxisDirection axisDirection: AxisDirection.down,
@required AxisDirection crossAxisDirection,
@required ViewportOffset offset, @required ViewportOffset offset,
List<RenderSliver> children, List<RenderSliver> children,
}) : super(axisDirection: axisDirection, offset: offset) { }) : super(axisDirection: axisDirection, crossAxisDirection: crossAxisDirection, offset: offset) {
addAll(children); addAll(children);
} }
......
...@@ -453,13 +453,8 @@ class _PageViewState extends State<PageView> { ...@@ -453,13 +453,8 @@ class _PageViewState extends State<PageView> {
case Axis.horizontal: case Axis.horizontal:
final TextDirection textDirection = Directionality.of(context); final TextDirection textDirection = Directionality.of(context);
assert(textDirection != null); assert(textDirection != null);
switch (textDirection) { final AxisDirection axisDirection = textDirectionToAxisDirection(textDirection);
case TextDirection.rtl: return widget.reverse ? flipAxisDirection(axisDirection) : axisDirection;
return widget.reverse ? AxisDirection.right : AxisDirection.left;
case TextDirection.ltr:
return widget.reverse ? AxisDirection.left : AxisDirection.right;
}
return null;
case Axis.vertical: case Axis.vertical:
return widget.reverse ? AxisDirection.up : AxisDirection.down; return widget.reverse ? AxisDirection.up : AxisDirection.down;
} }
......
...@@ -182,13 +182,8 @@ abstract class ScrollView extends StatelessWidget { ...@@ -182,13 +182,8 @@ abstract class ScrollView extends StatelessWidget {
case Axis.horizontal: case Axis.horizontal:
final TextDirection textDirection = Directionality.of(context); final TextDirection textDirection = Directionality.of(context);
assert(textDirection != null); assert(textDirection != null);
switch (textDirection) { final AxisDirection axisDirection = textDirectionToAxisDirection(textDirection);
case TextDirection.rtl: return reverse ? flipAxisDirection(axisDirection) : axisDirection;
return reverse ? AxisDirection.right : AxisDirection.left;
case TextDirection.ltr:
return reverse ? AxisDirection.left : AxisDirection.right;
}
return null;
case Axis.vertical: case Axis.vertical:
return reverse ? AxisDirection.up : AxisDirection.down; return reverse ? AxisDirection.up : AxisDirection.down;
} }
......
...@@ -119,13 +119,8 @@ class SingleChildScrollView extends StatelessWidget { ...@@ -119,13 +119,8 @@ class SingleChildScrollView extends StatelessWidget {
case Axis.horizontal: case Axis.horizontal:
final TextDirection textDirection = Directionality.of(context); final TextDirection textDirection = Directionality.of(context);
assert(textDirection != null); assert(textDirection != null);
switch (textDirection) { final AxisDirection axisDirection = textDirectionToAxisDirection(textDirection);
case TextDirection.rtl: return reverse ? flipAxisDirection(axisDirection) : axisDirection;
return reverse ? AxisDirection.right : AxisDirection.left;
case TextDirection.ltr:
return reverse ? AxisDirection.left : AxisDirection.right;
}
return null;
case Axis.vertical: case Axis.vertical:
return reverse ? AxisDirection.up : AxisDirection.down; return reverse ? AxisDirection.up : AxisDirection.down;
} }
......
...@@ -5,12 +5,28 @@ ...@@ -5,12 +5,28 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'basic.dart';
import 'framework.dart'; import 'framework.dart';
export 'package:flutter/rendering.dart' show export 'package:flutter/rendering.dart' show
AxisDirection, AxisDirection,
GrowthDirection; GrowthDirection;
AxisDirection _getDefaultCrossAxisDirection(BuildContext context, AxisDirection axisDirection) {
assert(axisDirection != null);
switch (axisDirection) {
case AxisDirection.up:
return textDirectionToAxisDirection(Directionality.of(context));
case AxisDirection.right:
return AxisDirection.down;
case AxisDirection.down:
return textDirectionToAxisDirection(Directionality.of(context));
case AxisDirection.left:
return AxisDirection.down;
}
return null;
}
/// A widget that is bigger on the inside. /// A widget that is bigger on the inside.
/// ///
/// [Viewport] is the visual workhorse of the scrolling machinery. It displays a /// [Viewport] is the visual workhorse of the scrolling machinery. It displays a
...@@ -52,6 +68,7 @@ class Viewport extends MultiChildRenderObjectWidget { ...@@ -52,6 +68,7 @@ class Viewport extends MultiChildRenderObjectWidget {
Viewport({ Viewport({
Key key, Key key,
this.axisDirection: AxisDirection.down, this.axisDirection: AxisDirection.down,
this.crossAxisDirection,
this.anchor: 0.0, this.anchor: 0.0,
@required this.offset, @required this.offset,
this.center, this.center,
...@@ -68,6 +85,17 @@ class Viewport extends MultiChildRenderObjectWidget { ...@@ -68,6 +85,17 @@ class Viewport extends MultiChildRenderObjectWidget {
/// bottom of the viewport. /// bottom of the viewport.
final AxisDirection axisDirection; final AxisDirection axisDirection;
/// The direction in which child should be laid out in the cross axis.
///
/// If the [axisDirection] is [AxisDirection.down] or [AxisDirection.up], this
/// property defaults to [AxisDirection.left] if the ambient [Directionality]
/// is [TextDirection.rtl] and [AxisDirection.right] if the ambient
/// [Directionality] is [TextDirection.ltr].
///
/// If the [axisDirection] is [AxisDirection.left] or [AxisDirection.right],
/// this property defaults to [AxisDirection.down].
final AxisDirection crossAxisDirection;
/// The relative position of the zero scroll offset. /// The relative position of the zero scroll offset.
/// ///
/// For example, if [anchor] is 0.5 and the [axisDirection] is /// For example, if [anchor] is 0.5 and the [axisDirection] is
...@@ -100,6 +128,7 @@ class Viewport extends MultiChildRenderObjectWidget { ...@@ -100,6 +128,7 @@ class Viewport extends MultiChildRenderObjectWidget {
RenderViewport createRenderObject(BuildContext context) { RenderViewport createRenderObject(BuildContext context) {
return new RenderViewport( return new RenderViewport(
axisDirection: axisDirection, axisDirection: axisDirection,
crossAxisDirection: crossAxisDirection ?? _getDefaultCrossAxisDirection(context, axisDirection),
anchor: anchor, anchor: anchor,
offset: offset, offset: offset,
); );
...@@ -107,9 +136,11 @@ class Viewport extends MultiChildRenderObjectWidget { ...@@ -107,9 +136,11 @@ class Viewport extends MultiChildRenderObjectWidget {
@override @override
void updateRenderObject(BuildContext context, RenderViewport renderObject) { void updateRenderObject(BuildContext context, RenderViewport renderObject) {
renderObject.axisDirection = axisDirection; renderObject
renderObject.anchor = anchor; ..axisDirection = axisDirection
renderObject.offset = offset; ..crossAxisDirection = crossAxisDirection ?? _getDefaultCrossAxisDirection(context, axisDirection)
..anchor = anchor
..offset = offset;
} }
@override @override
...@@ -119,6 +150,7 @@ class Viewport extends MultiChildRenderObjectWidget { ...@@ -119,6 +150,7 @@ class Viewport extends MultiChildRenderObjectWidget {
void debugFillProperties(DiagnosticPropertiesBuilder description) { void debugFillProperties(DiagnosticPropertiesBuilder description) {
super.debugFillProperties(description); super.debugFillProperties(description);
description.add(new EnumProperty<AxisDirection>('axisDirection', axisDirection)); description.add(new EnumProperty<AxisDirection>('axisDirection', axisDirection));
description.add(new EnumProperty<AxisDirection>('crossAxisDirection', crossAxisDirection, defaultValue: null));
description.add(new DoubleProperty('anchor', anchor)); description.add(new DoubleProperty('anchor', anchor));
description.add(new DiagnosticsProperty<ViewportOffset>('offset', offset)); description.add(new DiagnosticsProperty<ViewportOffset>('offset', offset));
if (center != null) { if (center != null) {
...@@ -201,6 +233,7 @@ class ShrinkWrappingViewport extends MultiChildRenderObjectWidget { ...@@ -201,6 +233,7 @@ class ShrinkWrappingViewport extends MultiChildRenderObjectWidget {
ShrinkWrappingViewport({ ShrinkWrappingViewport({
Key key, Key key,
this.axisDirection: AxisDirection.down, this.axisDirection: AxisDirection.down,
this.crossAxisDirection,
@required this.offset, @required this.offset,
List<Widget> slivers: const <Widget>[], List<Widget> slivers: const <Widget>[],
}) : assert(offset != null), }) : assert(offset != null),
...@@ -213,6 +246,17 @@ class ShrinkWrappingViewport extends MultiChildRenderObjectWidget { ...@@ -213,6 +246,17 @@ class ShrinkWrappingViewport extends MultiChildRenderObjectWidget {
/// bottom of the viewport. /// bottom of the viewport.
final AxisDirection axisDirection; final AxisDirection axisDirection;
/// The direction in which child should be laid out in the cross axis.
///
/// If the [axisDirection] is [AxisDirection.down] or [AxisDirection.up], this
/// property defaults to [AxisDirection.left] if the ambient [Directionality]
/// is [TextDirection.rtl] and [AxisDirection.right] if the ambient
/// [Directionality] is [TextDirection.ltr].
///
/// If the [axisDirection] is [AxisDirection.left] or [AxisDirection.right],
/// this property defaults to [AxisDirection.down].
final AxisDirection crossAxisDirection;
/// Which part of the content inside the viewport should be visible. /// Which part of the content inside the viewport should be visible.
/// ///
/// The [ViewportOffset.pixels] value determines the scroll offset that the /// The [ViewportOffset.pixels] value determines the scroll offset that the
...@@ -227,6 +271,7 @@ class ShrinkWrappingViewport extends MultiChildRenderObjectWidget { ...@@ -227,6 +271,7 @@ class ShrinkWrappingViewport extends MultiChildRenderObjectWidget {
RenderShrinkWrappingViewport createRenderObject(BuildContext context) { RenderShrinkWrappingViewport createRenderObject(BuildContext context) {
return new RenderShrinkWrappingViewport( return new RenderShrinkWrappingViewport(
axisDirection: axisDirection, axisDirection: axisDirection,
crossAxisDirection: crossAxisDirection ?? _getDefaultCrossAxisDirection(context, axisDirection),
offset: offset, offset: offset,
); );
} }
...@@ -235,6 +280,7 @@ class ShrinkWrappingViewport extends MultiChildRenderObjectWidget { ...@@ -235,6 +280,7 @@ class ShrinkWrappingViewport extends MultiChildRenderObjectWidget {
void updateRenderObject(BuildContext context, RenderShrinkWrappingViewport renderObject) { void updateRenderObject(BuildContext context, RenderShrinkWrappingViewport renderObject) {
renderObject renderObject
..axisDirection = axisDirection ..axisDirection = axisDirection
..crossAxisDirection = crossAxisDirection ?? _getDefaultCrossAxisDirection(context, axisDirection)
..offset = offset; ..offset = offset;
} }
...@@ -242,6 +288,7 @@ class ShrinkWrappingViewport extends MultiChildRenderObjectWidget { ...@@ -242,6 +288,7 @@ class ShrinkWrappingViewport extends MultiChildRenderObjectWidget {
void debugFillProperties(DiagnosticPropertiesBuilder description) { void debugFillProperties(DiagnosticPropertiesBuilder description) {
super.debugFillProperties(description); super.debugFillProperties(description);
description.add(new EnumProperty<AxisDirection>('axisDirection', axisDirection)); description.add(new EnumProperty<AxisDirection>('axisDirection', axisDirection));
description.add(new EnumProperty<AxisDirection>('crossAxisDirection', crossAxisDirection, defaultValue: null));
description.add(new DiagnosticsProperty<ViewportOffset>('offset', offset)); description.add(new DiagnosticsProperty<ViewportOffset>('offset', offset));
} }
} }
...@@ -121,19 +121,24 @@ void main() { ...@@ -121,19 +121,24 @@ void main() {
testWidgets('splashing survives scrolling when keep-alive is enabled', (WidgetTester tester) async { testWidgets('splashing survives scrolling when keep-alive is enabled', (WidgetTester tester) async {
Future<Null> runTest(bool keepAlive) async { Future<Null> runTest(bool keepAlive) async {
await tester.pumpWidget(new Material( await tester.pumpWidget(
child: new CompositedTransformFollower( // forces a layer, which makes the paints easier to separate out new Directionality(
link: new LayerLink(), textDirection: TextDirection.ltr,
child: new ListView( child: new Material(
addAutomaticKeepAlives: keepAlive, child: new CompositedTransformFollower( // forces a layer, which makes the paints easier to separate out
children: <Widget>[ link: new LayerLink(),
new Container(height: 500.0, child: new InkWell(onTap: () { }, child: const Placeholder())), child: new ListView(
new Container(height: 500.0), addAutomaticKeepAlives: keepAlive,
new Container(height: 500.0), children: <Widget>[
], new Container(height: 500.0, child: new InkWell(onTap: () { }, child: const Placeholder())),
new Container(height: 500.0),
new Container(height: 500.0),
],
),
),
), ),
), ),
)); );
expect(tester.renderObject<RenderProxyBox>(find.byType(PhysicalModel)).child, paintsNothing); expect(tester.renderObject<RenderProxyBox>(find.byType(PhysicalModel)).child, paintsNothing);
await tester.tap(find.byType(InkWell)); await tester.tap(find.byType(InkWell));
await tester.pump(); await tester.pump();
......
...@@ -60,41 +60,44 @@ void main() { ...@@ -60,41 +60,44 @@ void main() {
final List<Size> log = <Size>[]; final List<Size> log = <Size>[];
await tester.pumpWidget( await tester.pumpWidget(
new Column( new Directionality(
children: <Widget>[ textDirection: TextDirection.ltr,
new SizedBox( child: new Column(
width: 150.0, children: <Widget>[
height: 150.0, new SizedBox(
child: new CustomPaint( width: 150.0,
painter: new PaintRecorder(log), height: 150.0,
child: new CustomPaint(
painter: new PaintRecorder(log),
),
), ),
), new Expanded(
new Expanded( child: new Material(
child: new Material( child: new Column(
child: new Column( children: <Widget>[
children: <Widget>[ new Expanded(
new Expanded( child: new ListView(
child: new ListView( children: <Widget>[
children: <Widget>[ new Container(
new Container( height: 2000.0,
height: 2000.0, color: const Color(0xFF00FF00),
color: const Color(0xFF00FF00), ),
), ],
], ),
), ),
), new SizedBox(
new SizedBox( width: 100.0,
width: 100.0, height: 100.0,
height: 100.0, child: new CustomPaint(
child: new CustomPaint( painter: new PaintRecorder(log),
painter: new PaintRecorder(log), ),
), ),
), ],
], ),
), ),
), ),
), ],
], ),
), ),
); );
......
...@@ -23,16 +23,19 @@ void main() { ...@@ -23,16 +23,19 @@ void main() {
testWidgets('RefreshIndicator', (WidgetTester tester) async { testWidgets('RefreshIndicator', (WidgetTester tester) async {
refreshCalled = false; refreshCalled = false;
await tester.pumpWidget( await tester.pumpWidget(
new RefreshIndicator( new Directionality(
onRefresh: refresh, textDirection: TextDirection.ltr,
child: new ListView( child: new RefreshIndicator(
physics: const AlwaysScrollableScrollPhysics(), onRefresh: refresh,
children: <String>['A', 'B', 'C', 'D', 'E', 'F'].map((String item) { child: new ListView(
return new SizedBox( physics: const AlwaysScrollableScrollPhysics(),
height: 200.0, children: <String>['A', 'B', 'C', 'D', 'E', 'F'].map((String item) {
child: new Text(item), return new SizedBox(
); height: 200.0,
}).toList(), child: new Text(item),
);
}).toList(),
),
), ),
), ),
); );
...@@ -48,17 +51,20 @@ void main() { ...@@ -48,17 +51,20 @@ void main() {
testWidgets('RefreshIndicator - bottom', (WidgetTester tester) async { testWidgets('RefreshIndicator - bottom', (WidgetTester tester) async {
refreshCalled = false; refreshCalled = false;
await tester.pumpWidget( await tester.pumpWidget(
new RefreshIndicator( new Directionality(
onRefresh: refresh, textDirection: TextDirection.ltr,
child: new ListView( child: new RefreshIndicator(
reverse: true, onRefresh: refresh,
physics: const AlwaysScrollableScrollPhysics(), child: new ListView(
children: <Widget>[ reverse: true,
const SizedBox( physics: const AlwaysScrollableScrollPhysics(),
height: 200.0, children: <Widget>[
child: const Text('X'), const SizedBox(
), height: 200.0,
], child: const Text('X'),
),
],
),
), ),
), ),
); );
...@@ -74,16 +80,19 @@ void main() { ...@@ -74,16 +80,19 @@ void main() {
testWidgets('RefreshIndicator - top - position', (WidgetTester tester) async { testWidgets('RefreshIndicator - top - position', (WidgetTester tester) async {
refreshCalled = false; refreshCalled = false;
await tester.pumpWidget( await tester.pumpWidget(
new RefreshIndicator( new Directionality(
onRefresh: holdRefresh, textDirection: TextDirection.ltr,
child: new ListView( child: new RefreshIndicator(
physics: const AlwaysScrollableScrollPhysics(), onRefresh: holdRefresh,
children: <Widget>[ child: new ListView(
const SizedBox( physics: const AlwaysScrollableScrollPhysics(),
height: 200.0, children: <Widget>[
child: const Text('X'), const SizedBox(
), height: 200.0,
], child: const Text('X'),
),
],
),
), ),
), ),
); );
...@@ -98,17 +107,20 @@ void main() { ...@@ -98,17 +107,20 @@ void main() {
testWidgets('RefreshIndicator - bottom - position', (WidgetTester tester) async { testWidgets('RefreshIndicator - bottom - position', (WidgetTester tester) async {
refreshCalled = false; refreshCalled = false;
await tester.pumpWidget( await tester.pumpWidget(
new RefreshIndicator( new Directionality(
onRefresh: holdRefresh, textDirection: TextDirection.ltr,
child: new ListView( child: new RefreshIndicator(
reverse: true, onRefresh: holdRefresh,
physics: const AlwaysScrollableScrollPhysics(), child: new ListView(
children: <Widget>[ reverse: true,
const SizedBox( physics: const AlwaysScrollableScrollPhysics(),
height: 200.0, children: <Widget>[
child: const Text('X'), const SizedBox(
), height: 200.0,
], child: const Text('X'),
),
],
),
), ),
), ),
); );
...@@ -123,16 +135,19 @@ void main() { ...@@ -123,16 +135,19 @@ void main() {
testWidgets('RefreshIndicator - no movement', (WidgetTester tester) async { testWidgets('RefreshIndicator - no movement', (WidgetTester tester) async {
refreshCalled = false; refreshCalled = false;
await tester.pumpWidget( await tester.pumpWidget(
new RefreshIndicator( new Directionality(
onRefresh: refresh, textDirection: TextDirection.ltr,
child: new ListView( child: new RefreshIndicator(
physics: const AlwaysScrollableScrollPhysics(), onRefresh: refresh,
children: <Widget>[ child: new ListView(
const SizedBox( physics: const AlwaysScrollableScrollPhysics(),
height: 200.0, children: <Widget>[
child: const Text('X'), const SizedBox(
), height: 200.0,
], child: const Text('X'),
),
],
),
), ),
), ),
); );
...@@ -149,16 +164,19 @@ void main() { ...@@ -149,16 +164,19 @@ void main() {
testWidgets('RefreshIndicator - not enough', (WidgetTester tester) async { testWidgets('RefreshIndicator - not enough', (WidgetTester tester) async {
refreshCalled = false; refreshCalled = false;
await tester.pumpWidget( await tester.pumpWidget(
new RefreshIndicator( new Directionality(
onRefresh: refresh, textDirection: TextDirection.ltr,
child: new ListView( child: new RefreshIndicator(
physics: const AlwaysScrollableScrollPhysics(), onRefresh: refresh,
children: <Widget>[ child: new ListView(
const SizedBox( physics: const AlwaysScrollableScrollPhysics(),
height: 200.0, children: <Widget>[
child: const Text('X'), const SizedBox(
), height: 200.0,
], child: const Text('X'),
),
],
),
), ),
), ),
); );
...@@ -174,16 +192,19 @@ void main() { ...@@ -174,16 +192,19 @@ void main() {
testWidgets('RefreshIndicator - show - slow', (WidgetTester tester) async { testWidgets('RefreshIndicator - show - slow', (WidgetTester tester) async {
refreshCalled = false; refreshCalled = false;
await tester.pumpWidget( await tester.pumpWidget(
new RefreshIndicator( new Directionality(
onRefresh: holdRefresh, // this one never returns textDirection: TextDirection.ltr,
child: new ListView( child: new RefreshIndicator(
physics: const AlwaysScrollableScrollPhysics(), onRefresh: holdRefresh, // this one never returns
children: <Widget>[ child: new ListView(
const SizedBox( physics: const AlwaysScrollableScrollPhysics(),
height: 200.0, children: <Widget>[
child: const Text('X'), const SizedBox(
), height: 200.0,
], child: const Text('X'),
),
],
),
), ),
), ),
); );
...@@ -215,16 +236,19 @@ void main() { ...@@ -215,16 +236,19 @@ void main() {
testWidgets('RefreshIndicator - show - fast', (WidgetTester tester) async { testWidgets('RefreshIndicator - show - fast', (WidgetTester tester) async {
refreshCalled = false; refreshCalled = false;
await tester.pumpWidget( await tester.pumpWidget(
new RefreshIndicator( new Directionality(
onRefresh: refresh, textDirection: TextDirection.ltr,
child: new ListView( child: new RefreshIndicator(
physics: const AlwaysScrollableScrollPhysics(), onRefresh: refresh,
children: <Widget>[ child: new ListView(
const SizedBox( physics: const AlwaysScrollableScrollPhysics(),
height: 200.0, children: <Widget>[
child: const Text('X'), const SizedBox(
), height: 200.0,
], child: const Text('X'),
),
],
),
), ),
), ),
); );
...@@ -257,16 +281,19 @@ void main() { ...@@ -257,16 +281,19 @@ void main() {
testWidgets('RefreshIndicator - show - fast - twice', (WidgetTester tester) async { testWidgets('RefreshIndicator - show - fast - twice', (WidgetTester tester) async {
refreshCalled = false; refreshCalled = false;
await tester.pumpWidget( await tester.pumpWidget(
new RefreshIndicator( new Directionality(
onRefresh: refresh, textDirection: TextDirection.ltr,
child: new ListView( child: new RefreshIndicator(
physics: const AlwaysScrollableScrollPhysics(), onRefresh: refresh,
children: <Widget>[ child: new ListView(
const SizedBox( physics: const AlwaysScrollableScrollPhysics(),
height: 200.0, children: <Widget>[
child: const Text('X'), const SizedBox(
), height: 200.0,
], child: const Text('X'),
),
],
),
), ),
), ),
); );
......
...@@ -79,6 +79,7 @@ void main() { ...@@ -79,6 +79,7 @@ void main() {
RenderSliver s; RenderSliver s;
RenderBox b; RenderBox b;
final RenderViewport root = new RenderViewport( final RenderViewport root = new RenderViewport(
crossAxisDirection: AxisDirection.right,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
children: <RenderSliver>[ children: <RenderSliver>[
s = new RenderSliverPadding( s = new RenderSliverPadding(
...@@ -106,6 +107,7 @@ void main() { ...@@ -106,6 +107,7 @@ void main() {
final RenderBox b = new RenderPadding( final RenderBox b = new RenderPadding(
padding: const EdgeInsets.all(10.0), padding: const EdgeInsets.all(10.0),
child: new RenderViewport( child: new RenderViewport(
crossAxisDirection: AxisDirection.right,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
children: <RenderSliver>[ children: <RenderSliver>[
s = new RenderSliverPadding( s = new RenderSliverPadding(
......
...@@ -78,6 +78,7 @@ void main() { ...@@ -78,6 +78,7 @@ void main() {
); );
final RenderViewport root = new RenderViewport( final RenderViewport root = new RenderViewport(
axisDirection: AxisDirection.down, axisDirection: AxisDirection.down,
crossAxisDirection: AxisDirection.right,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
children: <RenderSliver>[ children: <RenderSliver>[
inner = childManager.createRenderObject(), inner = childManager.createRenderObject(),
...@@ -152,6 +153,7 @@ void main() { ...@@ -152,6 +153,7 @@ void main() {
); );
final RenderViewport root = new RenderViewport( final RenderViewport root = new RenderViewport(
axisDirection: AxisDirection.up, axisDirection: AxisDirection.up,
crossAxisDirection: AxisDirection.right,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
children: <RenderSliver>[ children: <RenderSliver>[
inner = childManager.createRenderObject(), inner = childManager.createRenderObject(),
...@@ -226,6 +228,7 @@ void main() { ...@@ -226,6 +228,7 @@ void main() {
); );
final RenderViewport root = new RenderViewport( final RenderViewport root = new RenderViewport(
axisDirection: AxisDirection.down, axisDirection: AxisDirection.down,
crossAxisDirection: AxisDirection.right,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
children: <RenderSliver>[ children: <RenderSliver>[
inner = childManager.createRenderObject(), inner = childManager.createRenderObject(),
......
...@@ -25,6 +25,7 @@ void main() { ...@@ -25,6 +25,7 @@ void main() {
overlap: 0.0, overlap: 0.0,
remainingPaintExtent: 0.0, remainingPaintExtent: 0.0,
crossAxisExtent: 0.0, crossAxisExtent: 0.0,
crossAxisDirection: AxisDirection.right,
viewportMainAxisExtent: 0.0, viewportMainAxisExtent: 0.0,
); );
final SliverConstraints b = a.copyWith(); final SliverConstraints b = a.copyWith();
...@@ -52,6 +53,7 @@ void main() { ...@@ -52,6 +53,7 @@ void main() {
overlap: 20.0, overlap: 20.0,
remainingPaintExtent: 30.0, remainingPaintExtent: 30.0,
crossAxisExtent: 40.0, crossAxisExtent: 40.0,
crossAxisDirection: AxisDirection.right,
viewportMainAxisExtent: 30.0, viewportMainAxisExtent: 30.0,
); );
expect(c, equals(d)); expect(c, equals(d));
......
...@@ -25,6 +25,7 @@ void main() { ...@@ -25,6 +25,7 @@ void main() {
RenderBox box; RenderBox box;
final RenderObject root = new RenderLayoutWatcher( final RenderObject root = new RenderLayoutWatcher(
viewport = new RenderViewport( viewport = new RenderViewport(
crossAxisDirection: AxisDirection.right,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
children: <RenderSliver>[ children: <RenderSliver>[
sliver = new RenderSliverToBoxAdapter(child: box = new RenderSizedBox(const Size(100.0, 400.0))), sliver = new RenderSliverToBoxAdapter(child: box = new RenderSizedBox(const Size(100.0, 400.0))),
......
...@@ -11,6 +11,7 @@ import 'rendering_tester.dart'; ...@@ -11,6 +11,7 @@ import 'rendering_tester.dart';
void main() { void main() {
test('RenderViewport basic test - no children', () { test('RenderViewport basic test - no children', () {
final RenderViewport root = new RenderViewport( final RenderViewport root = new RenderViewport(
crossAxisDirection: AxisDirection.right,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
); );
expect(root, hasAGoodToStringDeep); expect(root, hasAGoodToStringDeep);
...@@ -22,6 +23,7 @@ void main() { ...@@ -22,6 +23,7 @@ void main() {
' constraints: null\n' ' constraints: null\n'
' size: MISSING\n' ' size: MISSING\n'
' axisDirection: down\n' ' axisDirection: down\n'
' crossAxisDirection: right\n'
' offset: _FixedViewportOffset#00000(offset: 0.0)\n' ' offset: _FixedViewportOffset#00000(offset: 0.0)\n'
' anchor: 0.0\n' ' anchor: 0.0\n'
), ),
...@@ -37,6 +39,7 @@ void main() { ...@@ -37,6 +39,7 @@ void main() {
' constraints: BoxConstraints(w=800.0, h=600.0)\n' ' constraints: BoxConstraints(w=800.0, h=600.0)\n'
' size: Size(800.0, 600.0)\n' ' size: Size(800.0, 600.0)\n'
' axisDirection: down\n' ' axisDirection: down\n'
' crossAxisDirection: right\n'
' offset: _FixedViewportOffset#00000(offset: 900.0)\n' ' offset: _FixedViewportOffset#00000(offset: 900.0)\n'
' anchor: 0.0\n', ' anchor: 0.0\n',
), ),
...@@ -48,6 +51,7 @@ void main() { ...@@ -48,6 +51,7 @@ void main() {
test('RenderViewport basic test - down', () { test('RenderViewport basic test - down', () {
RenderBox a, b, c, d, e; RenderBox a, b, c, d, e;
final RenderViewport root = new RenderViewport( final RenderViewport root = new RenderViewport(
crossAxisDirection: AxisDirection.right,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
children: <RenderSliver>[ children: <RenderSliver>[
new RenderSliverToBoxAdapter(child: a = new RenderSizedBox(const Size(100.0, 400.0))), new RenderSliverToBoxAdapter(child: a = new RenderSizedBox(const Size(100.0, 400.0))),
...@@ -72,6 +76,7 @@ void main() { ...@@ -72,6 +76,7 @@ void main() {
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n' ' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
' │ size: Size(800.0, 600.0)\n' ' │ size: Size(800.0, 600.0)\n'
' │ axisDirection: down\n' ' │ axisDirection: down\n'
' │ crossAxisDirection: right\n'
' │ offset: _FixedViewportOffset#00000(offset: 0.0)\n' ' │ offset: _FixedViewportOffset#00000(offset: 0.0)\n'
' │ anchor: 0.0\n' ' │ anchor: 0.0\n'
' │\n' ' │\n'
...@@ -80,6 +85,7 @@ void main() { ...@@ -80,6 +85,7 @@ void main() {
' │ │ constraints: SliverConstraints(AxisDirection.down,\n' ' │ │ constraints: SliverConstraints(AxisDirection.down,\n'
' │ │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n' ' │ │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
' │ │ 0.0, remainingPaintExtent: 600.0, crossAxisExtent: 800.0,\n' ' │ │ 0.0, remainingPaintExtent: 600.0, crossAxisExtent: 800.0,\n'
' │ │ crossAxisDirection: AxisDirection.right,\n'
' │ │ viewportMainAxisExtent: 600.0)\n' ' │ │ viewportMainAxisExtent: 600.0)\n'
' │ │ geometry: SliverGeometry(scrollExtent: 400.0, paintExtent: 400.0,\n' ' │ │ geometry: SliverGeometry(scrollExtent: 400.0, paintExtent: 400.0,\n'
' │ │ maxPaintExtent: 400.0)\n' ' │ │ maxPaintExtent: 400.0)\n'
...@@ -94,6 +100,7 @@ void main() { ...@@ -94,6 +100,7 @@ void main() {
' │ │ constraints: SliverConstraints(AxisDirection.down,\n' ' │ │ constraints: SliverConstraints(AxisDirection.down,\n'
' │ │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n' ' │ │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
' │ │ 0.0, remainingPaintExtent: 200.0, crossAxisExtent: 800.0,\n' ' │ │ 0.0, remainingPaintExtent: 200.0, crossAxisExtent: 800.0,\n'
' │ │ crossAxisDirection: AxisDirection.right,\n'
' │ │ viewportMainAxisExtent: 600.0)\n' ' │ │ viewportMainAxisExtent: 600.0)\n'
' │ │ geometry: SliverGeometry(scrollExtent: 400.0, paintExtent: 200.0,\n' ' │ │ geometry: SliverGeometry(scrollExtent: 400.0, paintExtent: 200.0,\n'
' │ │ maxPaintExtent: 400.0, hasVisualOverflow: true)\n' ' │ │ maxPaintExtent: 400.0, hasVisualOverflow: true)\n'
...@@ -108,6 +115,7 @@ void main() { ...@@ -108,6 +115,7 @@ void main() {
' │ │ constraints: SliverConstraints(AxisDirection.down,\n' ' │ │ constraints: SliverConstraints(AxisDirection.down,\n'
' │ │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n' ' │ │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
' │ │ 0.0, remainingPaintExtent: 0.0, crossAxisExtent: 800.0,\n' ' │ │ 0.0, remainingPaintExtent: 0.0, crossAxisExtent: 800.0,\n'
' │ │ crossAxisDirection: AxisDirection.right,\n'
' │ │ viewportMainAxisExtent: 600.0)\n' ' │ │ viewportMainAxisExtent: 600.0)\n'
' │ │ geometry: SliverGeometry(scrollExtent: 400.0, hidden,\n' ' │ │ geometry: SliverGeometry(scrollExtent: 400.0, hidden,\n'
' │ │ maxPaintExtent: 400.0, hasVisualOverflow: true)\n' ' │ │ maxPaintExtent: 400.0, hasVisualOverflow: true)\n'
...@@ -122,6 +130,7 @@ void main() { ...@@ -122,6 +130,7 @@ void main() {
' │ │ constraints: SliverConstraints(AxisDirection.down,\n' ' │ │ constraints: SliverConstraints(AxisDirection.down,\n'
' │ │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n' ' │ │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
' │ │ 0.0, remainingPaintExtent: 0.0, crossAxisExtent: 800.0,\n' ' │ │ 0.0, remainingPaintExtent: 0.0, crossAxisExtent: 800.0,\n'
' │ │ crossAxisDirection: AxisDirection.right,\n'
' │ │ viewportMainAxisExtent: 600.0)\n' ' │ │ viewportMainAxisExtent: 600.0)\n'
' │ │ geometry: SliverGeometry(scrollExtent: 400.0, hidden,\n' ' │ │ geometry: SliverGeometry(scrollExtent: 400.0, hidden,\n'
' │ │ maxPaintExtent: 400.0, hasVisualOverflow: true)\n' ' │ │ maxPaintExtent: 400.0, hasVisualOverflow: true)\n'
...@@ -136,6 +145,7 @@ void main() { ...@@ -136,6 +145,7 @@ void main() {
' │ constraints: SliverConstraints(AxisDirection.down,\n' ' │ constraints: SliverConstraints(AxisDirection.down,\n'
' │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n' ' │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
' │ 0.0, remainingPaintExtent: 0.0, crossAxisExtent: 800.0,\n' ' │ 0.0, remainingPaintExtent: 0.0, crossAxisExtent: 800.0,\n'
' │ crossAxisDirection: AxisDirection.right,\n'
' │ viewportMainAxisExtent: 600.0)\n' ' │ viewportMainAxisExtent: 600.0)\n'
' │ geometry: SliverGeometry(scrollExtent: 400.0, hidden,\n' ' │ geometry: SliverGeometry(scrollExtent: 400.0, hidden,\n'
' │ maxPaintExtent: 400.0, hasVisualOverflow: true)\n' ' │ maxPaintExtent: 400.0, hasVisualOverflow: true)\n'
...@@ -143,7 +153,7 @@ void main() { ...@@ -143,7 +153,7 @@ void main() {
' └─child: RenderSizedBox#00000 NEEDS-PAINT\n' ' └─child: RenderSizedBox#00000 NEEDS-PAINT\n'
' parentData: paintOffset=Offset(0.0, -0.0) (can use size)\n' ' parentData: paintOffset=Offset(0.0, -0.0) (can use size)\n'
' constraints: BoxConstraints(w=800.0, 0.0<=h<=Infinity)\n' ' constraints: BoxConstraints(w=800.0, 0.0<=h<=Infinity)\n'
' size: Size(800.0, 400.0)\n', ' size: Size(800.0, 400.0)\n'
), ),
); );
expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 0.0)); expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 0.0));
...@@ -191,6 +201,7 @@ void main() { ...@@ -191,6 +201,7 @@ void main() {
RenderBox a, b, c, d, e; RenderBox a, b, c, d, e;
final RenderViewport root = new RenderViewport( final RenderViewport root = new RenderViewport(
axisDirection: AxisDirection.up, axisDirection: AxisDirection.up,
crossAxisDirection: AxisDirection.right,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
children: <RenderSliver>[ children: <RenderSliver>[
new RenderSliverToBoxAdapter(child: a = new RenderSizedBox(const Size(100.0, 400.0))), new RenderSliverToBoxAdapter(child: a = new RenderSizedBox(const Size(100.0, 400.0))),
...@@ -249,6 +260,7 @@ void main() { ...@@ -249,6 +260,7 @@ void main() {
RenderBox a, b, c, d, e; RenderBox a, b, c, d, e;
final RenderViewport root = new RenderViewport( final RenderViewport root = new RenderViewport(
axisDirection: AxisDirection.right, axisDirection: AxisDirection.right,
crossAxisDirection: AxisDirection.down,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
children: <RenderSliver>[ children: <RenderSliver>[
new RenderSliverToBoxAdapter(child: a = new RenderSizedBox(const Size(400.0, 100.0))), new RenderSliverToBoxAdapter(child: a = new RenderSizedBox(const Size(400.0, 100.0))),
...@@ -332,6 +344,7 @@ void main() { ...@@ -332,6 +344,7 @@ void main() {
RenderBox a, b, c, d, e; RenderBox a, b, c, d, e;
final RenderViewport root = new RenderViewport( final RenderViewport root = new RenderViewport(
axisDirection: AxisDirection.left, axisDirection: AxisDirection.left,
crossAxisDirection: AxisDirection.down,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
children: <RenderSliver>[ children: <RenderSliver>[
new RenderSliverToBoxAdapter(child: a = new RenderSizedBox(const Size(400.0, 100.0))), new RenderSliverToBoxAdapter(child: a = new RenderSizedBox(const Size(400.0, 100.0))),
...@@ -387,6 +400,7 @@ void main() { ...@@ -387,6 +400,7 @@ void main() {
test('RenderShrinkWrappingViewport basic test - no children', () { test('RenderShrinkWrappingViewport basic test - no children', () {
final RenderShrinkWrappingViewport root = new RenderShrinkWrappingViewport( final RenderShrinkWrappingViewport root = new RenderShrinkWrappingViewport(
crossAxisDirection: AxisDirection.right,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
); );
expect(root, hasAGoodToStringDeep); expect(root, hasAGoodToStringDeep);
...@@ -398,6 +412,7 @@ void main() { ...@@ -398,6 +412,7 @@ void main() {
test('RenderShrinkWrappingViewport basic test - down', () { test('RenderShrinkWrappingViewport basic test - down', () {
RenderBox a, b, c, d, e; RenderBox a, b, c, d, e;
final RenderShrinkWrappingViewport root = new RenderShrinkWrappingViewport( final RenderShrinkWrappingViewport root = new RenderShrinkWrappingViewport(
crossAxisDirection: AxisDirection.right,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
children: <RenderSliver>[ children: <RenderSliver>[
new RenderSliverToBoxAdapter(child: a = new RenderSizedBox(const Size(100.0, 400.0))), new RenderSliverToBoxAdapter(child: a = new RenderSizedBox(const Size(100.0, 400.0))),
...@@ -457,6 +472,7 @@ void main() { ...@@ -457,6 +472,7 @@ void main() {
RenderBox a, b, c, d, e; RenderBox a, b, c, d, e;
final RenderShrinkWrappingViewport root = new RenderShrinkWrappingViewport( final RenderShrinkWrappingViewport root = new RenderShrinkWrappingViewport(
axisDirection: AxisDirection.up, axisDirection: AxisDirection.up,
crossAxisDirection: AxisDirection.right,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
children: <RenderSliver>[ children: <RenderSliver>[
new RenderSliverToBoxAdapter(child: a = new RenderSizedBox(const Size(100.0, 400.0))), new RenderSliverToBoxAdapter(child: a = new RenderSizedBox(const Size(100.0, 400.0))),
...@@ -510,6 +526,7 @@ void main() { ...@@ -510,6 +526,7 @@ void main() {
RenderBox a, b, c, d, e; RenderBox a, b, c, d, e;
final RenderShrinkWrappingViewport root = new RenderShrinkWrappingViewport( final RenderShrinkWrappingViewport root = new RenderShrinkWrappingViewport(
axisDirection: AxisDirection.right, axisDirection: AxisDirection.right,
crossAxisDirection: AxisDirection.down,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
children: <RenderSliver>[ children: <RenderSliver>[
new RenderSliverToBoxAdapter(child: a = new RenderSizedBox(const Size(400.0, 100.0))), new RenderSliverToBoxAdapter(child: a = new RenderSizedBox(const Size(400.0, 100.0))),
...@@ -563,6 +580,7 @@ void main() { ...@@ -563,6 +580,7 @@ void main() {
RenderBox a, b, c, d, e; RenderBox a, b, c, d, e;
final RenderShrinkWrappingViewport root = new RenderShrinkWrappingViewport( final RenderShrinkWrappingViewport root = new RenderShrinkWrappingViewport(
axisDirection: AxisDirection.left, axisDirection: AxisDirection.left,
crossAxisDirection: AxisDirection.down,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
children: <RenderSliver>[ children: <RenderSliver>[
new RenderSliverToBoxAdapter(child: a = new RenderSizedBox(const Size(400.0, 100.0))), new RenderSliverToBoxAdapter(child: a = new RenderSizedBox(const Size(400.0, 100.0))),
...@@ -617,6 +635,7 @@ void main() { ...@@ -617,6 +635,7 @@ void main() {
final RenderBox root = new RenderPositionedBox( final RenderBox root = new RenderPositionedBox(
child: child = new RenderShrinkWrappingViewport( child: child = new RenderShrinkWrappingViewport(
axisDirection: AxisDirection.left, axisDirection: AxisDirection.left,
crossAxisDirection: AxisDirection.down,
offset: new ViewportOffset.fixed(200.0), offset: new ViewportOffset.fixed(200.0),
children: <RenderSliver>[ children: <RenderSliver>[
new RenderSliverToBoxAdapter(child: new RenderSizedBox(const Size(400.0, 100.0))), new RenderSliverToBoxAdapter(child: new RenderSizedBox(const Size(400.0, 100.0))),
...@@ -636,6 +655,7 @@ void main() { ...@@ -636,6 +655,7 @@ void main() {
final RenderBox root = new RenderPositionedBox( final RenderBox root = new RenderPositionedBox(
child: child = new RenderShrinkWrappingViewport( child: child = new RenderShrinkWrappingViewport(
axisDirection: AxisDirection.right, axisDirection: AxisDirection.right,
crossAxisDirection: AxisDirection.down,
offset: new ViewportOffset.fixed(200.0), offset: new ViewportOffset.fixed(200.0),
children: <RenderSliver>[ children: <RenderSliver>[
new RenderSliverToBoxAdapter(child: new RenderSizedBox(const Size(300.0, 100.0))), new RenderSliverToBoxAdapter(child: new RenderSizedBox(const Size(300.0, 100.0))),
...@@ -687,6 +707,7 @@ void main() { ...@@ -687,6 +707,7 @@ void main() {
); );
final RenderViewport root = new RenderViewport( final RenderViewport root = new RenderViewport(
axisDirection: AxisDirection.down, axisDirection: AxisDirection.down,
crossAxisDirection: AxisDirection.right,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
children: <RenderSliver>[ children: <RenderSliver>[
sliver, sliver,
...@@ -708,6 +729,7 @@ void main() { ...@@ -708,6 +729,7 @@ void main() {
); );
final RenderViewport root = new RenderViewport( final RenderViewport root = new RenderViewport(
axisDirection: AxisDirection.right, axisDirection: AxisDirection.right,
crossAxisDirection: AxisDirection.down,
offset: new ViewportOffset.zero(), offset: new ViewportOffset.zero(),
children: <RenderSliver>[ children: <RenderSliver>[
sliver, sliver,
......
...@@ -10,17 +10,20 @@ void main() { ...@@ -10,17 +10,20 @@ void main() {
final Map<int, Animation<double>> animations = <int, Animation<double>>{}; final Map<int, Animation<double>> animations = <int, Animation<double>>{};
await tester.pumpWidget( await tester.pumpWidget(
new AnimatedList( new Directionality(
initialItemCount: 2, textDirection: TextDirection.ltr,
itemBuilder: (BuildContext context, int index, Animation<double> animation) { child: new AnimatedList(
animations[index] = animation; initialItemCount: 2,
return new SizedBox( itemBuilder: (BuildContext context, int index, Animation<double> animation) {
height: 100.0, animations[index] = animation;
child: new Center( return new SizedBox(
child: new Text('item $index'), height: 100.0,
), child: new Center(
); child: new Text('item $index'),
}, ),
);
},
),
), ),
); );
...@@ -36,21 +39,24 @@ void main() { ...@@ -36,21 +39,24 @@ void main() {
final GlobalKey<AnimatedListState> listKey = new GlobalKey<AnimatedListState>(); final GlobalKey<AnimatedListState> listKey = new GlobalKey<AnimatedListState>();
await tester.pumpWidget( await tester.pumpWidget(
new AnimatedList( new Directionality(
key: listKey, textDirection: TextDirection.ltr,
itemBuilder: (BuildContext context, int index, Animation<double> animation) { child: new AnimatedList(
return new SizeTransition( key: listKey,
key: new ValueKey<int>(index), itemBuilder: (BuildContext context, int index, Animation<double> animation) {
axis: Axis.vertical, return new SizeTransition(
sizeFactor: animation, key: new ValueKey<int>(index),
child: new SizedBox( axis: Axis.vertical,
height: 100.0, sizeFactor: animation,
child: new Center( child: new SizedBox(
child: new Text('item $index'), height: 100.0,
child: new Center(
child: new Text('item $index'),
),
), ),
), );
); },
}, ),
), ),
); );
...@@ -122,12 +128,15 @@ void main() { ...@@ -122,12 +128,15 @@ void main() {
} }
await tester.pumpWidget( await tester.pumpWidget(
new AnimatedList( new Directionality(
key: listKey, textDirection: TextDirection.ltr,
initialItemCount: 3, child: new AnimatedList(
itemBuilder: (BuildContext context, int index, Animation<double> animation) { key: listKey,
return buildItem(context, items[index], animation); initialItemCount: 3,
}, itemBuilder: (BuildContext context, int index, Animation<double> animation) {
return buildItem(context, items[index], animation);
},
),
), ),
); );
......
...@@ -65,12 +65,17 @@ List<Widget> generateList(Widget child, { @required bool impliedMode }) { ...@@ -65,12 +65,17 @@ List<Widget> generateList(Widget child, { @required bool impliedMode }) {
void tests({ @required bool impliedMode }) { void tests({ @required bool impliedMode }) {
testWidgets('AutomaticKeepAlive with ListView with itemExtent', (WidgetTester tester) async { testWidgets('AutomaticKeepAlive with ListView with itemExtent', (WidgetTester tester) async {
await tester.pumpWidget(new ListView( await tester.pumpWidget(
addAutomaticKeepAlives: impliedMode, new Directionality(
addRepaintBoundaries: impliedMode, textDirection: TextDirection.ltr,
itemExtent: 12.3, // about 50 widgets visible child: new ListView(
children: generateList(const Placeholder(), impliedMode: impliedMode), addAutomaticKeepAlives: impliedMode,
)); addRepaintBoundaries: impliedMode,
itemExtent: 12.3, // about 50 widgets visible
children: generateList(const Placeholder(), impliedMode: impliedMode),
),
),
);
expect(find.byKey(const GlobalObjectKey<_LeafState>(3)), findsOneWidget); expect(find.byKey(const GlobalObjectKey<_LeafState>(3)), findsOneWidget);
expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget); expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget);
expect(find.byKey(const GlobalObjectKey<_LeafState>(59)), findsNothing); expect(find.byKey(const GlobalObjectKey<_LeafState>(59)), findsNothing);
...@@ -105,14 +110,19 @@ void tests({ @required bool impliedMode }) { ...@@ -105,14 +110,19 @@ void tests({ @required bool impliedMode }) {
}); });
testWidgets('AutomaticKeepAlive with ListView without itemExtent', (WidgetTester tester) async { testWidgets('AutomaticKeepAlive with ListView without itemExtent', (WidgetTester tester) async {
await tester.pumpWidget(new ListView( await tester.pumpWidget(
addAutomaticKeepAlives: impliedMode, new Directionality(
addRepaintBoundaries: impliedMode, textDirection: TextDirection.ltr,
children: generateList( child: new ListView(
new Container(height: 12.3, child: const Placeholder()), // about 50 widgets visible addAutomaticKeepAlives: impliedMode,
impliedMode: impliedMode, addRepaintBoundaries: impliedMode,
children: generateList(
new Container(height: 12.3, child: const Placeholder()), // about 50 widgets visible
impliedMode: impliedMode,
),
),
), ),
)); );
expect(find.byKey(const GlobalObjectKey<_LeafState>(3)), findsOneWidget); expect(find.byKey(const GlobalObjectKey<_LeafState>(3)), findsOneWidget);
expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget); expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget);
expect(find.byKey(const GlobalObjectKey<_LeafState>(59)), findsNothing); expect(find.byKey(const GlobalObjectKey<_LeafState>(59)), findsNothing);
...@@ -147,16 +157,21 @@ void tests({ @required bool impliedMode }) { ...@@ -147,16 +157,21 @@ void tests({ @required bool impliedMode }) {
}); });
testWidgets('AutomaticKeepAlive with GridView', (WidgetTester tester) async { testWidgets('AutomaticKeepAlive with GridView', (WidgetTester tester) async {
await tester.pumpWidget(new GridView.count( await tester.pumpWidget(
addAutomaticKeepAlives: impliedMode, new Directionality(
addRepaintBoundaries: impliedMode, textDirection: TextDirection.ltr,
crossAxisCount: 2, child: new GridView.count(
childAspectRatio: 400.0 / 24.6, // about 50 widgets visible addAutomaticKeepAlives: impliedMode,
children: generateList( addRepaintBoundaries: impliedMode,
new Container(child: const Placeholder()), crossAxisCount: 2,
impliedMode: impliedMode, childAspectRatio: 400.0 / 24.6, // about 50 widgets visible
children: generateList(
new Container(child: const Placeholder()),
impliedMode: impliedMode,
),
),
), ),
)); );
expect(find.byKey(const GlobalObjectKey<_LeafState>(3)), findsOneWidget); expect(find.byKey(const GlobalObjectKey<_LeafState>(3)), findsOneWidget);
expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget); expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget);
expect(find.byKey(const GlobalObjectKey<_LeafState>(59)), findsNothing); expect(find.byKey(const GlobalObjectKey<_LeafState>(59)), findsNothing);
...@@ -196,36 +211,38 @@ void main() { ...@@ -196,36 +211,38 @@ void main() {
group('Implied automatic keep-alive', () { tests(impliedMode: true); }); group('Implied automatic keep-alive', () { tests(impliedMode: true); });
testWidgets('AutomaticKeepAlive double', (WidgetTester tester) async { testWidgets('AutomaticKeepAlive double', (WidgetTester tester) async {
await tester.pumpWidget(new Directionality( await tester.pumpWidget(
textDirection: TextDirection.ltr, new Directionality(
child: new ListView( textDirection: TextDirection.ltr,
addAutomaticKeepAlives: false, child: new ListView(
addRepaintBoundaries: false, addAutomaticKeepAlives: false,
children: <Widget>[ addRepaintBoundaries: false,
new AutomaticKeepAlive( children: <Widget>[
child: new Container( new AutomaticKeepAlive(
height: 400.0, child: new Container(
child: new Row(children: <Widget>[ height: 400.0,
new Leaf(key: const GlobalObjectKey<_LeafState>(0), child: const Placeholder()), child: new Row(children: <Widget>[
new Leaf(key: const GlobalObjectKey<_LeafState>(1), child: const Placeholder()), new Leaf(key: const GlobalObjectKey<_LeafState>(0), child: const Placeholder()),
]), new Leaf(key: const GlobalObjectKey<_LeafState>(1), child: const Placeholder()),
]),
),
), ),
), new AutomaticKeepAlive(
new AutomaticKeepAlive( child: new Container(
child: new Container( key: const GlobalObjectKey<_LeafState>(2),
key: const GlobalObjectKey<_LeafState>(2), height: 400.0,
height: 400.0, ),
), ),
), new AutomaticKeepAlive(
new AutomaticKeepAlive( child: new Container(
child: new Container( key: const GlobalObjectKey<_LeafState>(3),
key: const GlobalObjectKey<_LeafState>(3), height: 400.0,
height: 400.0, ),
), ),
), ],
], ),
), ),
)); );
expect(find.byKey(const GlobalObjectKey<_LeafState>(0)), findsOneWidget); expect(find.byKey(const GlobalObjectKey<_LeafState>(0)), findsOneWidget);
expect(find.byKey(const GlobalObjectKey<_LeafState>(1)), findsOneWidget); expect(find.byKey(const GlobalObjectKey<_LeafState>(1)), findsOneWidget);
expect(find.byKey(const GlobalObjectKey<_LeafState>(2)), findsOneWidget); expect(find.byKey(const GlobalObjectKey<_LeafState>(2)), findsOneWidget);
...@@ -270,42 +287,44 @@ void main() { ...@@ -270,42 +287,44 @@ void main() {
}); });
testWidgets('AutomaticKeepAlive double', (WidgetTester tester) async { testWidgets('AutomaticKeepAlive double', (WidgetTester tester) async {
await tester.pumpWidget(new Directionality( await tester.pumpWidget(
textDirection: TextDirection.ltr, new Directionality(
child: new ListView( textDirection: TextDirection.ltr,
addAutomaticKeepAlives: false, child: new ListView(
addRepaintBoundaries: false, addAutomaticKeepAlives: false,
children: <Widget>[ addRepaintBoundaries: false,
new AutomaticKeepAlive( children: <Widget>[
child: new Container( new AutomaticKeepAlive(
height: 400.0, child: new Container(
child: new Row(children: <Widget>[ height: 400.0,
new Leaf(key: const GlobalObjectKey<_LeafState>(0), child: const Placeholder()), child: new Row(children: <Widget>[
new Leaf(key: const GlobalObjectKey<_LeafState>(1), child: const Placeholder()), new Leaf(key: const GlobalObjectKey<_LeafState>(0), child: const Placeholder()),
]), new Leaf(key: const GlobalObjectKey<_LeafState>(1), child: const Placeholder()),
]),
),
), ),
), new AutomaticKeepAlive(
new AutomaticKeepAlive( child: new Container(
child: new Container( height: 400.0,
height: 400.0, child: new Row(children: <Widget>[
child: new Row(children: <Widget>[ new Leaf(key: const GlobalObjectKey<_LeafState>(2), child: const Placeholder()),
new Leaf(key: const GlobalObjectKey<_LeafState>(2), child: const Placeholder()), new Leaf(key: const GlobalObjectKey<_LeafState>(3), child: const Placeholder()),
new Leaf(key: const GlobalObjectKey<_LeafState>(3), child: const Placeholder()), ]),
]), ),
), ),
), new AutomaticKeepAlive(
new AutomaticKeepAlive( child: new Container(
child: new Container( height: 400.0,
height: 400.0, child: new Row(children: <Widget>[
child: new Row(children: <Widget>[ new Leaf(key: const GlobalObjectKey<_LeafState>(4), child: const Placeholder()),
new Leaf(key: const GlobalObjectKey<_LeafState>(4), child: const Placeholder()), new Leaf(key: const GlobalObjectKey<_LeafState>(5), child: const Placeholder()),
new Leaf(key: const GlobalObjectKey<_LeafState>(5), child: const Placeholder()), ]),
]), ),
), ),
), ],
], ),
), ),
)); );
expect(find.byKey(const GlobalObjectKey<_LeafState>(0)), findsOneWidget); expect(find.byKey(const GlobalObjectKey<_LeafState>(0)), findsOneWidget);
expect(find.byKey(const GlobalObjectKey<_LeafState>(1)), findsOneWidget); expect(find.byKey(const GlobalObjectKey<_LeafState>(1)), findsOneWidget);
expect(find.byKey(const GlobalObjectKey<_LeafState>(2)), findsOneWidget); expect(find.byKey(const GlobalObjectKey<_LeafState>(2)), findsOneWidget);
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
void main() { void main() {
...@@ -33,24 +34,28 @@ void main() { ...@@ -33,24 +34,28 @@ void main() {
testWidgets('Box in a sliver', (WidgetTester tester) async { testWidgets('Box in a sliver', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
new CustomScrollView( new Viewport(
crossAxisDirection: AxisDirection.right,
offset: new ViewportOffset.zero(),
slivers: <Widget>[ slivers: <Widget>[
const SizedBox(), const SizedBox(),
], ],
) ),
); );
expect(tester.takeException(), isFlutterError); expect(tester.takeException(), isFlutterError);
await tester.pumpWidget( await tester.pumpWidget(
new CustomScrollView( new Viewport(
crossAxisDirection: AxisDirection.right,
offset: new ViewportOffset.zero(),
slivers: <Widget>[ slivers: <Widget>[
const SliverPadding( const SliverPadding(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
sliver: const SizedBox(), sliver: const SizedBox(),
), ),
], ],
) ),
); );
expect(tester.takeException(), isFlutterError); expect(tester.takeException(), isFlutterError);
......
...@@ -7,6 +7,11 @@ import 'package:flutter/widgets.dart'; ...@@ -7,6 +7,11 @@ import 'package:flutter/widgets.dart';
void main() { void main() {
testWidgets('Can be placed in an infinite box', (WidgetTester tester) async { testWidgets('Can be placed in an infinite box', (WidgetTester tester) async {
await tester.pumpWidget(new ListView(children: <Widget>[const Center()])); await tester.pumpWidget(
new Directionality(
textDirection: TextDirection.ltr,
child: new ListView(children: <Widget>[const Center()])
),
);
}); });
} }
...@@ -135,6 +135,11 @@ void main() { ...@@ -135,6 +135,11 @@ void main() {
}); });
testWidgets('Can be placed in an infinite box', (WidgetTester tester) async { testWidgets('Can be placed in an infinite box', (WidgetTester tester) async {
await tester.pumpWidget(new ListView(children: <Widget>[new Container()])); await tester.pumpWidget(
new Directionality(
textDirection: TextDirection.ltr,
child: new ListView(children: <Widget>[new Container()]),
),
);
}); });
} }
...@@ -9,19 +9,22 @@ void main() { ...@@ -9,19 +9,22 @@ void main() {
testWidgets('Can select a day', (WidgetTester tester) async { testWidgets('Can select a day', (WidgetTester tester) async {
DateTime currentValue; DateTime currentValue;
final Widget widget = new Material( final Widget widget = new Directionality(
child: new ListView( textDirection: TextDirection.ltr,
children: <Widget>[ child: new Material(
new MonthPicker( child: new ListView(
selectedDate: new DateTime.utc(2015, 6, 9, 7, 12), children: <Widget>[
firstDate: new DateTime.utc(2013), new MonthPicker(
lastDate: new DateTime.utc(2018), selectedDate: new DateTime.utc(2015, 6, 9, 7, 12),
onChanged: (DateTime dateTime) { firstDate: new DateTime.utc(2013),
currentValue = dateTime; lastDate: new DateTime.utc(2018),
} onChanged: (DateTime dateTime) {
) currentValue = dateTime;
] },
) ),
],
),
),
); );
await tester.pumpWidget(widget); await tester.pumpWidget(widget);
......
...@@ -387,29 +387,34 @@ void main() { ...@@ -387,29 +387,34 @@ void main() {
); );
} }
await tester.pumpWidget(new Center( await tester.pumpWidget(
child: new SizedBox( new Directionality(
width: 600.0, textDirection: TextDirection.ltr,
height: 400.0, child: new Center(
child: new Scrollable( child: new SizedBox(
viewportBuilder: (BuildContext context, ViewportOffset offset) { width: 600.0,
return new Viewport( height: 400.0,
offset: offset, child: new Scrollable(
center: const ValueKey<int>(4), viewportBuilder: (BuildContext context, ViewportOffset offset) {
slivers: <Widget>[ return new Viewport(
buildSliver(0), offset: offset,
buildSliver(1), center: const ValueKey<int>(4),
buildSliver(2), slivers: <Widget>[
buildSliver(3), buildSliver(0),
buildSliver(4), buildSliver(1),
buildSliver(5), buildSliver(2),
buildSliver(6), buildSliver(3),
], buildSliver(4),
); buildSliver(5),
}, buildSliver(6),
],
);
},
),
),
), ),
), ),
)); );
await prepare(-125.0); await prepare(-125.0);
Scrollable.ensureVisible(findContext(3)); Scrollable.ensureVisible(findContext(3));
...@@ -628,35 +633,40 @@ void main() { ...@@ -628,35 +633,40 @@ void main() {
await tester.pump(); await tester.pump();
} }
await tester.pumpWidget(new Center( await tester.pumpWidget(
child: new SizedBox( new Directionality(
width: 600.0, textDirection: TextDirection.ltr,
height: 400.0, child: new Center(
child: new Scrollable( child: new SizedBox(
viewportBuilder: (BuildContext context, ViewportOffset offset) { width: 600.0,
return new Viewport( height: 400.0,
offset: offset, child: new Scrollable(
center: const ValueKey<String>('center'), viewportBuilder: (BuildContext context, ViewportOffset offset) {
slivers: <Widget>[ return new Viewport(
new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(-6), width: 200.0, height: 200.0)), offset: offset,
new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(-5), width: 200.0, height: 200.0)), center: const ValueKey<String>('center'),
new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(-4), width: 200.0, height: 200.0)), slivers: <Widget>[
new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(-3), width: 200.0, height: 200.0)), new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(-6), width: 200.0, height: 200.0)),
new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(-2), width: 200.0, height: 200.0)), new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(-5), width: 200.0, height: 200.0)),
new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(-1), width: 200.0, height: 200.0)), new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(-4), width: 200.0, height: 200.0)),
new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(0), width: 200.0, height: 200.0), key: const ValueKey<String>('center')), new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(-3), width: 200.0, height: 200.0)),
new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(1), width: 200.0, height: 200.0)), new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(-2), width: 200.0, height: 200.0)),
new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(2), width: 200.0, height: 200.0)), new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(-1), width: 200.0, height: 200.0)),
new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(3), width: 200.0, height: 200.0)), new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(0), width: 200.0, height: 200.0), key: const ValueKey<String>('center')),
new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(4), width: 200.0, height: 200.0)), new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(1), width: 200.0, height: 200.0)),
new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(5), width: 200.0, height: 200.0)), new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(2), width: 200.0, height: 200.0)),
new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(6), width: 200.0, height: 200.0)), new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(3), width: 200.0, height: 200.0)),
], new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(4), width: 200.0, height: 200.0)),
); new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(5), width: 200.0, height: 200.0)),
}, new SliverToBoxAdapter(child: new Container(key: const ValueKey<int>(6), width: 200.0, height: 200.0)),
],
);
},
),
),
), ),
), ),
)); );
await prepare(480.0); await prepare(480.0);
Scrollable.ensureVisible(findContext(3)); Scrollable.ensureVisible(findContext(3));
......
...@@ -118,20 +118,23 @@ void main() { ...@@ -118,20 +118,23 @@ void main() {
String errorText(String input) => fieldKey.currentState.value?.toString() + '/error'; String errorText(String input) => fieldKey.currentState.value?.toString() + '/error';
Widget builder() { Widget builder() {
return new Center( return new Directionality(
child: new Material( textDirection: TextDirection.ltr,
child: new Form( child: new Center(
key: formKey, child: new Material(
autovalidate: true, child: new Form(
child: new ListView( key: formKey,
children: <Widget>[ autovalidate: true,
new TextFormField( child: new ListView(
key: fieldKey, children: <Widget>[
), new TextFormField(
new TextFormField( key: fieldKey,
validator: errorText, ),
), new TextFormField(
], validator: errorText,
),
],
),
), ),
), ),
), ),
......
...@@ -14,16 +14,21 @@ void main() { ...@@ -14,16 +14,21 @@ void main() {
const DecoratedBox(decoration: const BoxDecoration()), const DecoratedBox(decoration: const BoxDecoration()),
]; ];
await tester.pumpWidget(new Center( await tester.pumpWidget(
child: new Container( new Directionality(
width: 200.0, textDirection: TextDirection.ltr,
child: new GridView.extent( child: new Center(
maxCrossAxisExtent: 100.0, child: new Container(
shrinkWrap: true, width: 200.0,
children: children, child: new GridView.extent(
maxCrossAxisExtent: 100.0,
shrinkWrap: true,
children: children,
),
),
), ),
), ),
)); );
expect(tester.renderObjectList<RenderBox>(find.byType(DecoratedBox)), hasLength(4)); expect(tester.renderObjectList<RenderBox>(find.byType(DecoratedBox)), hasLength(4));
...@@ -38,16 +43,21 @@ void main() { ...@@ -38,16 +43,21 @@ void main() {
expect(grid.debugNeedsLayout, false); expect(grid.debugNeedsLayout, false);
await tester.pumpWidget(new Center( await tester.pumpWidget(
child: new Container( new Directionality(
width: 200.0, textDirection: TextDirection.ltr,
child: new GridView.extent( child: new Center(
maxCrossAxisExtent: 60.0, child: new Container(
shrinkWrap: true, width: 200.0,
children: children, child: new GridView.extent(
maxCrossAxisExtent: 60.0,
shrinkWrap: true,
children: children,
),
),
), ),
), ),
)); );
for (RenderBox box in tester.renderObjectList<RenderBox>(find.byType(DecoratedBox))) { for (RenderBox box in tester.renderObjectList<RenderBox>(find.byType(DecoratedBox))) {
expect(box.size.width, equals(50.0), reason: "child width"); expect(box.size.width, equals(50.0), reason: "child width");
......
...@@ -282,80 +282,83 @@ class _TestState extends State<Test> { ...@@ -282,80 +282,83 @@ class _TestState extends State<Test> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new Column( return new Directionality(
children: <Widget>[ textDirection: TextDirection.ltr,
new Expanded( child: new Column(
child: new ListView( children: <Widget>[
controller: _beforeController, new Expanded(
children: <Widget>[ child: new ListView(
new Container( controller: _beforeController,
margin: const EdgeInsets.all(8.0), children: <Widget>[
padding: const EdgeInsets.all(8.0), new Container(
height: 250.0, margin: const EdgeInsets.all(8.0),
color: const Color(0xFF90F090), padding: const EdgeInsets.all(8.0),
child: const Center(child: const Text('Hello A')), height: 250.0,
), color: const Color(0xFF90F090),
new Container( child: const Center(child: const Text('Hello A')),
margin: const EdgeInsets.all(8.0), ),
padding: const EdgeInsets.all(8.0), new Container(
height: 250.0, margin: const EdgeInsets.all(8.0),
color: const Color(0xFF90F090), padding: const EdgeInsets.all(8.0),
child: const Center(child: const Text('Hello B')), height: 250.0,
), color: const Color(0xFF90F090),
new Container( child: const Center(child: const Text('Hello B')),
margin: const EdgeInsets.all(8.0), ),
padding: const EdgeInsets.all(8.0), new Container(
height: 250.0, margin: const EdgeInsets.all(8.0),
color: const Color(0xFF90F090), padding: const EdgeInsets.all(8.0),
child: const Center(child: const Text('Hello C')), height: 250.0,
), color: const Color(0xFF90F090),
new Container( child: const Center(child: const Text('Hello C')),
margin: const EdgeInsets.all(8.0), ),
padding: const EdgeInsets.all(8.0), new Container(
height: 250.0, margin: const EdgeInsets.all(8.0),
color: const Color(0xFF90F090), padding: const EdgeInsets.all(8.0),
child: const Center(child: const Text('Hello D')), height: 250.0,
), color: const Color(0xFF90F090),
], child: const Center(child: const Text('Hello D')),
),
],
),
), ),
), const Divider(),
const Divider(), new Expanded(
new Expanded( child: new ListView(
child: new ListView( controller: _afterController,
controller: _afterController, children: <Widget>[
children: <Widget>[ new Container(
new Container( margin: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.all(8.0), height: 250.0,
height: 250.0, color: const Color(0xFF9090F0),
color: const Color(0xFF9090F0), child: const Center(child: const Text('Hello 1')),
child: const Center(child: const Text('Hello 1')), ),
), new Container(
new Container( margin: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.all(8.0), height: 250.0,
height: 250.0, color: const Color(0xFF9090F0),
color: const Color(0xFF9090F0), child: const Center(child: const Text('Hello 2')),
child: const Center(child: const Text('Hello 2')), ),
), new Container(
new Container( margin: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.all(8.0), height: 250.0,
height: 250.0, color: const Color(0xFF9090F0),
color: const Color(0xFF9090F0), child: const Center(child: const Text('Hello 3')),
child: const Center(child: const Text('Hello 3')), ),
), new Container(
new Container( margin: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.all(8.0), height: 250.0,
height: 250.0, color: const Color(0xFF9090F0),
color: const Color(0xFF9090F0), child: const Center(child: const Text('Hello 4')),
child: const Center(child: const Text('Hello 4')), ),
), ],
], ),
), ),
), ],
], ),
); );
} }
} }
......
...@@ -15,19 +15,22 @@ void main() { ...@@ -15,19 +15,22 @@ void main() {
// so if our widget is 100 pixels tall, it should fit exactly 6 times. // so if our widget is 100 pixels tall, it should fit exactly 6 times.
Widget builder() { Widget builder() {
return new FlipWidget( return new Directionality(
left: new ListView.builder( textDirection: TextDirection.ltr,
itemExtent: 100.0, child: new FlipWidget(
itemBuilder: (BuildContext context, int index) { left: new ListView.builder(
callbackTracker.add(index); itemExtent: 100.0,
return new Container( itemBuilder: (BuildContext context, int index) {
key: new ValueKey<int>(index), callbackTracker.add(index);
height: 100.0, return new Container(
child: new Text('$index'), key: new ValueKey<int>(index),
); height: 100.0,
}, child: new Text('$index'),
);
},
),
right: const Text('Not Today'),
), ),
right: const Text('Not Today'),
); );
} }
...@@ -67,14 +70,17 @@ void main() { ...@@ -67,14 +70,17 @@ void main() {
); );
}; };
FlipWidget buildWidget() { Widget buildWidget() {
return new FlipWidget( return new Directionality(
left: new ListView.builder( textDirection: TextDirection.ltr,
controller: new ScrollController(initialScrollOffset: 300.0), child: new FlipWidget(
itemExtent: 200.0, left: new ListView.builder(
itemBuilder: itemBuilder, controller: new ScrollController(initialScrollOffset: 300.0),
itemExtent: 200.0,
itemBuilder: itemBuilder,
),
right: const Text('Not Today')
), ),
right: const Text('Not Today')
); );
} }
...@@ -187,10 +193,13 @@ void main() { ...@@ -187,10 +193,13 @@ void main() {
return new Text('$index', key: new ValueKey<int>(index)); return new Text('$index', key: new ValueKey<int>(index));
}; };
final Widget testWidget = new ListView.builder( final Widget testWidget = new Directionality(
itemBuilder: itemBuilder, textDirection: TextDirection.ltr,
itemExtent: 300.0, child: new ListView.builder(
itemCount: 10, itemBuilder: itemBuilder,
itemExtent: 300.0,
itemCount: 10,
),
); );
void jumpTo(double newScrollOffset) { void jumpTo(double newScrollOffset) {
......
...@@ -8,34 +8,44 @@ import 'package:flutter/material.dart'; ...@@ -8,34 +8,44 @@ import 'package:flutter/material.dart';
void main() { void main() {
testWidgets('ListView can handle shrinking top elements', (WidgetTester tester) async { testWidgets('ListView can handle shrinking top elements', (WidgetTester tester) async {
final ScrollController controller = new ScrollController(); final ScrollController controller = new ScrollController();
await tester.pumpWidget(new ListView( await tester.pumpWidget(
controller: controller, new Directionality(
children: <Widget>[ textDirection: TextDirection.ltr,
new Container(height: 400.0, child: const Text('1')), child: new ListView(
new Container(height: 400.0, child: const Text('2')), controller: controller,
new Container(height: 400.0, child: const Text('3')), children: <Widget>[
new Container(height: 400.0, child: const Text('4')), new Container(height: 400.0, child: const Text('1')),
new Container(height: 400.0, child: const Text('5')), new Container(height: 400.0, child: const Text('2')),
new Container(height: 400.0, child: const Text('6')), new Container(height: 400.0, child: const Text('3')),
], new Container(height: 400.0, child: const Text('4')),
)); new Container(height: 400.0, child: const Text('5')),
new Container(height: 400.0, child: const Text('6')),
],
),
),
);
controller.jumpTo(1000.0); controller.jumpTo(1000.0);
await tester.pump(); await tester.pump();
expect(tester.getTopLeft(find.text('4')).dy, equals(200.0)); expect(tester.getTopLeft(find.text('4')).dy, equals(200.0));
await tester.pumpWidget(new ListView( await tester.pumpWidget(
controller: controller, new Directionality(
children: <Widget>[ textDirection: TextDirection.ltr,
new Container(height: 200.0, child: const Text('1')), child: new ListView(
new Container(height: 400.0, child: const Text('2')), controller: controller,
new Container(height: 400.0, child: const Text('3')), children: <Widget>[
new Container(height: 400.0, child: const Text('4')), new Container(height: 200.0, child: const Text('1')),
new Container(height: 400.0, child: const Text('5')), new Container(height: 400.0, child: const Text('2')),
new Container(height: 400.0, child: const Text('6')), new Container(height: 400.0, child: const Text('3')),
], new Container(height: 400.0, child: const Text('4')),
)); new Container(height: 400.0, child: const Text('5')),
new Container(height: 400.0, child: const Text('6')),
],
),
),
);
expect(controller.offset, equals(1000.0)); expect(controller.offset, equals(1000.0));
expect(tester.getTopLeft(find.text('4')).dy, equals(200.0)); expect(tester.getTopLeft(find.text('4')).dy, equals(200.0));
...@@ -55,15 +65,20 @@ void main() { ...@@ -55,15 +65,20 @@ void main() {
testWidgets('ListView can handle inserts at 0', (WidgetTester tester) async { testWidgets('ListView can handle inserts at 0', (WidgetTester tester) async {
final ScrollController controller = new ScrollController(); final ScrollController controller = new ScrollController();
await tester.pumpWidget(new ListView( await tester.pumpWidget(
controller: controller, new Directionality(
children: <Widget>[ textDirection: TextDirection.ltr,
new Container(height: 400.0, child: const Text('0')), child: new ListView(
new Container(height: 400.0, child: const Text('1')), controller: controller,
new Container(height: 400.0, child: const Text('2')), children: <Widget>[
new Container(height: 400.0, child: const Text('3')), new Container(height: 400.0, child: const Text('0')),
], new Container(height: 400.0, child: const Text('1')),
)); new Container(height: 400.0, child: const Text('2')),
new Container(height: 400.0, child: const Text('3')),
],
),
),
);
expect(find.text('0'), findsOneWidget); expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsOneWidget); expect(find.text('1'), findsOneWidget);
expect(find.text('2'), findsNothing); expect(find.text('2'), findsNothing);
...@@ -71,17 +86,22 @@ void main() { ...@@ -71,17 +86,22 @@ void main() {
final Finder findItemA = find.descendant(of: find.byType(Container), matching: find.text('A')); final Finder findItemA = find.descendant(of: find.byType(Container), matching: find.text('A'));
final Finder findItemB = find.descendant(of: find.byType(Container), matching: find.text('B')); final Finder findItemB = find.descendant(of: find.byType(Container), matching: find.text('B'));
await tester.pumpWidget(new ListView( await tester.pumpWidget(
controller: controller, new Directionality(
children: <Widget>[ textDirection: TextDirection.ltr,
new Container(height: 10.0, child: const Text('A')), child: new ListView(
new Container(height: 10.0, child: const Text('B')), controller: controller,
new Container(height: 400.0, child: const Text('0')), children: <Widget>[
new Container(height: 400.0, child: const Text('1')), new Container(height: 10.0, child: const Text('A')),
new Container(height: 400.0, child: const Text('2')), new Container(height: 10.0, child: const Text('B')),
new Container(height: 400.0, child: const Text('3')), new Container(height: 400.0, child: const Text('0')),
], new Container(height: 400.0, child: const Text('1')),
)); new Container(height: 400.0, child: const Text('2')),
new Container(height: 400.0, child: const Text('3')),
],
),
),
);
expect(find.text('A'), findsOneWidget); expect(find.text('A'), findsOneWidget);
expect(find.text('B'), findsOneWidget); expect(find.text('B'), findsOneWidget);
expect(tester.getTopLeft(findItemA).dy, 0.0); expect(tester.getTopLeft(findItemA).dy, 0.0);
...@@ -95,17 +115,22 @@ void main() { ...@@ -95,17 +115,22 @@ void main() {
expect(find.text('A'), findsNothing); expect(find.text('A'), findsNothing);
expect(find.text('B'), findsNothing); expect(find.text('B'), findsNothing);
await tester.pumpWidget(new ListView( await tester.pumpWidget(
controller: controller, new Directionality(
children: <Widget>[ textDirection: TextDirection.ltr,
new Container(height: 200.0, child: const Text('A')), child: new ListView(
new Container(height: 200.0, child: const Text('B')), controller: controller,
new Container(height: 400.0, child: const Text('0')), children: <Widget>[
new Container(height: 400.0, child: const Text('1')), new Container(height: 200.0, child: const Text('A')),
new Container(height: 400.0, child: const Text('2')), new Container(height: 200.0, child: const Text('B')),
new Container(height: 400.0, child: const Text('3')), new Container(height: 400.0, child: const Text('0')),
], new Container(height: 400.0, child: const Text('1')),
)); new Container(height: 400.0, child: const Text('2')),
new Container(height: 400.0, child: const Text('3')),
],
),
),
);
expect(find.text('A'), findsNothing); expect(find.text('A'), findsNothing);
expect(find.text('B'), findsNothing); expect(find.text('B'), findsNothing);
......
...@@ -10,11 +10,16 @@ const double kFlingOffset = kHeight * 20.0; ...@@ -10,11 +10,16 @@ const double kFlingOffset = kHeight * 20.0;
void main() { void main() {
testWidgets('Flings don\'t stutter', (WidgetTester tester) async { testWidgets('Flings don\'t stutter', (WidgetTester tester) async {
await tester.pumpWidget(new ListView.builder( await tester.pumpWidget(
itemBuilder: (BuildContext context, int index) { new Directionality(
return new Container(height: kHeight); textDirection: TextDirection.ltr,
}, child: new ListView.builder(
)); itemBuilder: (BuildContext context, int index) {
return new Container(height: kHeight);
},
),
),
);
double getCurrentOffset() { double getCurrentOffset() {
return tester.state<ScrollableState>(find.byType(Scrollable)).position.pixels; return tester.state<ScrollableState>(find.byType(Scrollable)).position.pixels;
......
...@@ -11,15 +11,18 @@ final Key blockKey = const Key('test'); ...@@ -11,15 +11,18 @@ final Key blockKey = const Key('test');
void main() { void main() {
testWidgets('Cannot scroll a non-overflowing block', (WidgetTester tester) async { testWidgets('Cannot scroll a non-overflowing block', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
new ListView( new Directionality(
key: blockKey, textDirection: TextDirection.ltr,
children: <Widget>[ child: new ListView(
new Container( key: blockKey,
height: 200.0, // less than 600, the height of the test area children: <Widget>[
child: const Text('Hello') new Container(
) height: 200.0, // less than 600, the height of the test area
] child: const Text('Hello'),
) ),
],
),
),
); );
final Offset middleOfContainer = tester.getCenter(find.text('Hello')); final Offset middleOfContainer = tester.getCenter(find.text('Hello'));
...@@ -36,15 +39,18 @@ void main() { ...@@ -36,15 +39,18 @@ void main() {
testWidgets('Can scroll an overflowing block', (WidgetTester tester) async { testWidgets('Can scroll an overflowing block', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
new ListView( new Directionality(
key: blockKey, textDirection: TextDirection.ltr,
children: <Widget>[ child: new ListView(
new Container( key: blockKey,
height: 2000.0, // more than 600, the height of the test area children: <Widget>[
child: const Text('Hello') new Container(
) height: 2000.0, // more than 600, the height of the test area
] child: const Text('Hello'),
) ),
],
),
),
); );
final Offset middleOfContainer = tester.getCenter(find.text('Hello')); final Offset middleOfContainer = tester.getCenter(find.text('Hello'));
...@@ -67,25 +73,28 @@ void main() { ...@@ -67,25 +73,28 @@ void main() {
int second = 0; int second = 0;
Widget buildBlock({ bool reverse: false }) { Widget buildBlock({ bool reverse: false }) {
return new ListView( return new Directionality(
key: new UniqueKey(), textDirection: TextDirection.ltr,
reverse: reverse, child: new ListView(
children: <Widget>[ key: new UniqueKey(),
new GestureDetector( reverse: reverse,
onTap: () { first += 1; }, children: <Widget>[
child: new Container( new GestureDetector(
height: 350.0, // more than half the height of the test area onTap: () { first += 1; },
color: const Color(0xFF00FF00), child: new Container(
) height: 350.0, // more than half the height of the test area
), color: const Color(0xFF00FF00),
new GestureDetector( )
onTap: () { second += 1; }, ),
child: new Container( new GestureDetector(
height: 350.0, // more than half the height of the test area onTap: () { second += 1; },
color: const Color(0xFF0000FF), child: new Container(
) height: 350.0, // more than half the height of the test area
) color: const Color(0xFF0000FF),
] ),
),
],
),
); );
} }
...@@ -107,9 +116,12 @@ void main() { ...@@ -107,9 +116,12 @@ void main() {
final ScrollController controller = new ScrollController(); final ScrollController controller = new ScrollController();
Widget buildBlock() { Widget buildBlock() {
return new ListView( return new Directionality(
controller: controller, textDirection: TextDirection.ltr,
children: <Widget>[const Text("A"), const Text("B"), const Text("C")] child: new ListView(
controller: controller,
children: <Widget>[const Text("A"), const Text("B"), const Text("C")],
),
); );
} }
await tester.pumpWidget(buildBlock()); await tester.pumpWidget(buildBlock());
...@@ -125,13 +137,18 @@ void main() { ...@@ -125,13 +137,18 @@ void main() {
new Container(), new Container(),
]); ]);
await tester.pumpWidget(new CustomScrollView( await tester.pumpWidget(
slivers: <Widget>[ new Directionality(
new SliverList( textDirection: TextDirection.ltr,
delegate: delegate, child: new CustomScrollView(
slivers: <Widget>[
new SliverList(
delegate: delegate,
),
],
), ),
], ),
)); );
final SliverMultiBoxAdaptorElement element = tester.element(find.byType(SliverList)); final SliverMultiBoxAdaptorElement element = tester.element(find.byType(SliverList));
...@@ -154,42 +171,45 @@ void main() { ...@@ -154,42 +171,45 @@ void main() {
// The overall height of the frame is (as ever) 600 // The overall height of the frame is (as ever) 600
Widget buildFrame() { Widget buildFrame() {
return new Column( return new Directionality(
children: <Widget>[ textDirection: TextDirection.ltr,
new Flexible( child: new Column(
// The overall height of the ListView's contents is 500 children: <Widget>[
child: new ListView( new Flexible(
children: <Widget>[ // The overall height of the ListView's contents is 500
const SizedBox( child: new ListView(
height: 150.0, children: <Widget>[
child: const Center( const SizedBox(
child: const Text('top') height: 150.0,
child: const Center(
child: const Text('top')
),
), ),
), const SizedBox(
const SizedBox( height: 200.0,
height: 200.0, child: const Center(
child: const Center( child: const Text('middle')
child: const Text('middle') ),
), ),
), const SizedBox(
const SizedBox( height: 150.0,
height: 150.0, child: const Center(
child: const Center( child: const Text('bottom')
child: const Text('bottom') ),
), ),
), ],
], ),
), ),
), // If this widget's height is > 100 the ListView can scroll.
// If this widget's height is > 100 the ListView can scroll. new SizeTransition(
new SizeTransition( sizeFactor: controller.view,
sizeFactor: controller.view, child: const SizedBox(
child: const SizedBox( height: 300.0,
height: 300.0, child: const Text('keyboard'),
child: const Text('keyboard'), ),
), ),
), ],
], ),
); );
} }
......
...@@ -8,118 +8,173 @@ import 'package:flutter/rendering.dart'; ...@@ -8,118 +8,173 @@ import 'package:flutter/rendering.dart';
void main() { void main() {
testWidgets('Nested ListView with shrinkWrap', (WidgetTester tester) async { testWidgets('Nested ListView with shrinkWrap', (WidgetTester tester) async {
await tester.pumpWidget(new ListView( await tester.pumpWidget(
shrinkWrap: true, new Directionality(
children: <Widget>[ textDirection: TextDirection.ltr,
new ListView( child: new ListView(
shrinkWrap: true, shrinkWrap: true,
children: <Widget>[ children: <Widget>[
const Text('1'), new ListView(
const Text('2'), shrinkWrap: true,
const Text('3'), children: <Widget>[
const Text('1'),
const Text('2'),
const Text('3'),
],
),
new ListView(
shrinkWrap: true,
children: <Widget>[
const Text('4'),
const Text('5'),
const Text('6'),
],
),
], ],
), ),
new ListView( ),
shrinkWrap: true, );
children: <Widget>[
const Text('4'),
const Text('5'),
const Text('6'),
],
),
],
));
}); });
testWidgets('Underflowing ListView should relayout for additional children', (WidgetTester tester) async { testWidgets('Underflowing ListView should relayout for additional children', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/5950 // Regression test for https://github.com/flutter/flutter/issues/5950
await tester.pumpWidget(new ListView( await tester.pumpWidget(
children: <Widget>[ new Directionality(
const SizedBox(height: 100.0, child: const Text('100')), textDirection: TextDirection.ltr,
], child: new ListView(
)); children: <Widget>[
const SizedBox(height: 100.0, child: const Text('100')),
],
),
),
);
await tester.pumpWidget(new ListView( await tester.pumpWidget(
children: <Widget>[ new Directionality(
const SizedBox(height: 100.0, child: const Text('100')), textDirection: TextDirection.ltr,
const SizedBox(height: 200.0, child: const Text('200')), child: new ListView(
], children: <Widget>[
)); const SizedBox(height: 100.0, child: const Text('100')),
const SizedBox(height: 200.0, child: const Text('200')),
],
),
),
);
expect(find.text('200'), findsOneWidget); expect(find.text('200'), findsOneWidget);
}); });
testWidgets('Underflowing ListView contentExtent should track additional children', (WidgetTester tester) async { testWidgets('Underflowing ListView contentExtent should track additional children', (WidgetTester tester) async {
await tester.pumpWidget(new ListView( await tester.pumpWidget(
children: <Widget>[ new Directionality(
const SizedBox(height: 100.0, child: const Text('100')), textDirection: TextDirection.ltr,
], child: new ListView(
)); children: <Widget>[
const SizedBox(height: 100.0, child: const Text('100')),
],
),
),
);
final RenderSliverList list = tester.renderObject(find.byType(SliverList)); final RenderSliverList list = tester.renderObject(find.byType(SliverList));
expect(list.geometry.scrollExtent, equals(100.0)); expect(list.geometry.scrollExtent, equals(100.0));
await tester.pumpWidget(new ListView( await tester.pumpWidget(
children: <Widget>[ new Directionality(
const SizedBox(height: 100.0, child: const Text('100')), textDirection: TextDirection.ltr,
const SizedBox(height: 200.0, child: const Text('200')), child: new ListView(
], children: <Widget>[
)); const SizedBox(height: 100.0, child: const Text('100')),
const SizedBox(height: 200.0, child: const Text('200')),
],
),
),
);
expect(list.geometry.scrollExtent, equals(300.0)); expect(list.geometry.scrollExtent, equals(300.0));
await tester.pumpWidget(new ListView( await tester.pumpWidget(
children: <Widget>[] new Directionality(
)); textDirection: TextDirection.ltr,
child: new ListView(
children: <Widget>[]
),
),
);
expect(list.geometry.scrollExtent, equals(0.0)); expect(list.geometry.scrollExtent, equals(0.0));
}); });
testWidgets('Overflowing ListView should relayout for missing children', (WidgetTester tester) async { testWidgets('Overflowing ListView should relayout for missing children', (WidgetTester tester) async {
await tester.pumpWidget(new ListView( await tester.pumpWidget(
children: <Widget>[ new Directionality(
const SizedBox(height: 300.0, child: const Text('300')), textDirection: TextDirection.ltr,
const SizedBox(height: 400.0, child: const Text('400')), child: new ListView(
], children: <Widget>[
)); const SizedBox(height: 300.0, child: const Text('300')),
const SizedBox(height: 400.0, child: const Text('400')),
],
),
),
);
expect(find.text('300'), findsOneWidget); expect(find.text('300'), findsOneWidget);
expect(find.text('400'), findsOneWidget); expect(find.text('400'), findsOneWidget);
await tester.pumpWidget(new ListView( await tester.pumpWidget(
children: <Widget>[ new Directionality(
const SizedBox(height: 300.0, child: const Text('300')), textDirection: TextDirection.ltr,
], child: new ListView(
)); children: <Widget>[
const SizedBox(height: 300.0, child: const Text('300')),
],
),
),
);
expect(find.text('300'), findsOneWidget); expect(find.text('300'), findsOneWidget);
expect(find.text('400'), findsNothing); expect(find.text('400'), findsNothing);
await tester.pumpWidget(new ListView( await tester.pumpWidget(
children: <Widget>[] new Directionality(
)); textDirection: TextDirection.ltr,
child: new ListView(
children: <Widget>[]
),
),
);
expect(find.text('300'), findsNothing); expect(find.text('300'), findsNothing);
expect(find.text('400'), findsNothing); expect(find.text('400'), findsNothing);
}); });
testWidgets('Overflowing ListView should not relayout for additional children', (WidgetTester tester) async { testWidgets('Overflowing ListView should not relayout for additional children', (WidgetTester tester) async {
await tester.pumpWidget(new ListView( await tester.pumpWidget(
children: <Widget>[ new Directionality(
const SizedBox(height: 300.0, child: const Text('300')), textDirection: TextDirection.ltr,
const SizedBox(height: 400.0, child: const Text('400')), child: new ListView(
], children: <Widget>[
)); const SizedBox(height: 300.0, child: const Text('300')),
const SizedBox(height: 400.0, child: const Text('400')),
],
),
),
);
expect(find.text('300'), findsOneWidget); expect(find.text('300'), findsOneWidget);
expect(find.text('400'), findsOneWidget); expect(find.text('400'), findsOneWidget);
await tester.pumpWidget(new ListView( await tester.pumpWidget(
children: <Widget>[ new Directionality(
const SizedBox(height: 300.0, child: const Text('300')), textDirection: TextDirection.ltr,
const SizedBox(height: 400.0, child: const Text('400')), child: new ListView(
const SizedBox(height: 100.0, child: const Text('100')), children: <Widget>[
], const SizedBox(height: 300.0, child: const Text('300')),
)); const SizedBox(height: 400.0, child: const Text('400')),
const SizedBox(height: 100.0, child: const Text('100')),
],
),
),
);
expect(find.text('300'), findsOneWidget); expect(find.text('300'), findsOneWidget);
expect(find.text('400'), findsOneWidget); expect(find.text('400'), findsOneWidget);
...@@ -132,22 +187,32 @@ void main() { ...@@ -132,22 +187,32 @@ void main() {
// When children are added that cause it to overflow, scrolling should // When children are added that cause it to overflow, scrolling should
// be enabled. // be enabled.
await tester.pumpWidget(new ListView( await tester.pumpWidget(
children: <Widget>[ new Directionality(
const SizedBox(height: 100.0, child: const Text('100')), textDirection: TextDirection.ltr,
], child: new ListView(
)); children: <Widget>[
const SizedBox(height: 100.0, child: const Text('100')),
],
),
),
);
final ScrollableState scrollable = tester.state(find.byType(Scrollable)); final ScrollableState scrollable = tester.state(find.byType(Scrollable));
expect(scrollable.position.maxScrollExtent, 0.0); expect(scrollable.position.maxScrollExtent, 0.0);
await tester.pumpWidget(new ListView( await tester.pumpWidget(
children: <Widget>[ new Directionality(
const SizedBox(height: 100.0, child: const Text('100')), textDirection: TextDirection.ltr,
const SizedBox(height: 200.0, child: const Text('200')), child: new ListView(
const SizedBox(height: 400.0, child: const Text('400')), children: <Widget>[
], const SizedBox(height: 100.0, child: const Text('100')),
)); const SizedBox(height: 200.0, child: const Text('200')),
const SizedBox(height: 400.0, child: const Text('400')),
],
),
),
);
expect(scrollable.position.maxScrollExtent, 100.0); expect(scrollable.position.maxScrollExtent, 100.0);
}); });
......
...@@ -18,18 +18,28 @@ class TestSliverChildListDelegate extends SliverChildListDelegate { ...@@ -18,18 +18,28 @@ class TestSliverChildListDelegate extends SliverChildListDelegate {
void main() { void main() {
testWidgets('ListView default control', (WidgetTester tester) async { testWidgets('ListView default control', (WidgetTester tester) async {
await tester.pumpWidget(new Center(child: new ListView(itemExtent: 100.0))); await tester.pumpWidget(
new Directionality(
textDirection: TextDirection.ltr,
child: new Center(
child: new ListView(itemExtent: 100.0),
),
),
);
}); });
testWidgets('ListView itemExtent control test', (WidgetTester tester) async { testWidgets('ListView itemExtent control test', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
new ListView( new Directionality(
itemExtent: 200.0, textDirection: TextDirection.ltr,
children: new List<Widget>.generate(20, (int i) { child: new ListView(
return new Container( itemExtent: 200.0,
child: new Text('$i'), children: new List<Widget>.generate(20, (int i) {
); return new Container(
}), child: new Text('$i'),
);
}),
),
), ),
); );
...@@ -68,18 +78,21 @@ void main() { ...@@ -68,18 +78,21 @@ void main() {
final List<int> log = <int>[]; final List<int> log = <int>[];
await tester.pumpWidget( await tester.pumpWidget(
new ListView( new Directionality(
itemExtent: 200.0, textDirection: TextDirection.ltr,
children: new List<Widget>.generate(20, (int i) { child: new ListView(
return new Builder( itemExtent: 200.0,
builder: (BuildContext context) { children: new List<Widget>.generate(20, (int i) {
log.add(i); return new Builder(
return new Container( builder: (BuildContext context) {
child: new Text('$i'), log.add(i);
); return new Container(
} child: new Text('$i'),
); );
}), }
);
}),
),
), ),
); );
...@@ -107,8 +120,11 @@ void main() { ...@@ -107,8 +120,11 @@ void main() {
testWidgets('ListView can build out of underflow', (WidgetTester tester) async { testWidgets('ListView can build out of underflow', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
new ListView( new Directionality(
itemExtent: 100.0, textDirection: TextDirection.ltr,
child: new ListView(
itemExtent: 100.0,
),
), ),
); );
...@@ -120,13 +136,16 @@ void main() { ...@@ -120,13 +136,16 @@ void main() {
expect(find.text('5'), findsNothing); expect(find.text('5'), findsNothing);
await tester.pumpWidget( await tester.pumpWidget(
new ListView( new Directionality(
itemExtent: 100.0, textDirection: TextDirection.ltr,
children: new List<Widget>.generate(2, (int i) { child: new ListView(
return new Container( itemExtent: 100.0,
child: new Text('$i'), children: new List<Widget>.generate(2, (int i) {
); return new Container(
}), child: new Text('$i'),
);
}),
),
), ),
); );
...@@ -138,13 +157,16 @@ void main() { ...@@ -138,13 +157,16 @@ void main() {
expect(find.text('5'), findsNothing); expect(find.text('5'), findsNothing);
await tester.pumpWidget( await tester.pumpWidget(
new ListView( new Directionality(
itemExtent: 100.0, textDirection: TextDirection.ltr,
children: new List<Widget>.generate(5, (int i) { child: new ListView(
return new Container( itemExtent: 100.0,
child: new Text('$i'), children: new List<Widget>.generate(5, (int i) {
); return new Container(
}), child: new Text('$i'),
);
}),
),
), ),
); );
...@@ -158,15 +180,18 @@ void main() { ...@@ -158,15 +180,18 @@ void main() {
testWidgets('ListView can build out of overflow padding', (WidgetTester tester) async { testWidgets('ListView can build out of overflow padding', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
new Center( new Directionality(
child: new SizedBox( textDirection: TextDirection.ltr,
width: 0.0, child: new Center(
height: 0.0, child: new SizedBox(
child: new ListView( width: 0.0,
padding: const EdgeInsets.all(8.0), height: 0.0,
children: <Widget>[ child: new ListView(
const Text('padded'), padding: const EdgeInsets.all(8.0),
], children: <Widget>[
const Text('padded'),
],
),
), ),
), ),
), ),
...@@ -176,15 +201,18 @@ void main() { ...@@ -176,15 +201,18 @@ void main() {
testWidgets('ListView with itemExtent in unbounded context', (WidgetTester tester) async { testWidgets('ListView with itemExtent in unbounded context', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
new SingleChildScrollView( new Directionality(
child: new ListView( textDirection: TextDirection.ltr,
itemExtent: 100.0, child: new SingleChildScrollView(
shrinkWrap: true, child: new ListView(
children: new List<Widget>.generate(20, (int i) { itemExtent: 100.0,
return new Container( shrinkWrap: true,
child: new Text('$i'), children: new List<Widget>.generate(20, (int i) {
); return new Container(
}), child: new Text('$i'),
);
}),
),
), ),
), ),
); );
...@@ -203,9 +231,12 @@ void main() { ...@@ -203,9 +231,12 @@ void main() {
); );
await tester.pumpWidget( await tester.pumpWidget(
new ListView.custom( new Directionality(
itemExtent: 110.0, textDirection: TextDirection.ltr,
childrenDelegate: delegate, child: new ListView.custom(
itemExtent: 110.0,
childrenDelegate: delegate,
),
), ),
); );
...@@ -213,9 +244,12 @@ void main() { ...@@ -213,9 +244,12 @@ void main() {
delegate.log.clear(); delegate.log.clear();
await tester.pumpWidget( await tester.pumpWidget(
new ListView.custom( new Directionality(
itemExtent: 210.0, textDirection: TextDirection.ltr,
childrenDelegate: delegate, child: new ListView.custom(
itemExtent: 210.0,
childrenDelegate: delegate,
),
), ),
); );
......
...@@ -8,14 +8,17 @@ import 'package:flutter/widgets.dart'; ...@@ -8,14 +8,17 @@ import 'package:flutter/widgets.dart';
const List<int> items = const <int>[0, 1, 2, 3, 4, 5]; const List<int> items = const <int>[0, 1, 2, 3, 4, 5];
Widget buildFrame() { Widget buildFrame() {
return new ListView( return new Directionality(
itemExtent: 290.0, textDirection: TextDirection.ltr,
scrollDirection: Axis.vertical, child: new ListView(
children: items.map((int item) { itemExtent: 290.0,
return new Container( scrollDirection: Axis.vertical,
child: new Text('$item') children: items.map((int item) {
); return new Container(
}).toList(), child: new Text('$item')
);
}).toList(),
),
); );
} }
...@@ -65,15 +68,18 @@ void main() { ...@@ -65,15 +68,18 @@ void main() {
testWidgets('Drag vertically', (WidgetTester tester) async { testWidgets('Drag vertically', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
new ListView( new Directionality(
itemExtent: 290.0, textDirection: TextDirection.ltr,
padding: const EdgeInsets.only(top: 250.0), child: new ListView(
scrollDirection: Axis.vertical, itemExtent: 290.0,
children: items.map((int item) { padding: const EdgeInsets.only(top: 250.0),
return new Container( scrollDirection: Axis.vertical,
child: new Text('$item') children: items.map((int item) {
); return new Container(
}).toList(), child: new Text('$item')
);
}).toList(),
),
), ),
); );
......
...@@ -16,18 +16,21 @@ void main() { ...@@ -16,18 +16,21 @@ void main() {
// so if our widget is 100 pixels tall, it should fit exactly 6 times. // so if our widget is 100 pixels tall, it should fit exactly 6 times.
Widget builder() { Widget builder() {
return new FlipWidget( return new Directionality(
left: new ListView.builder( textDirection: TextDirection.ltr,
itemBuilder: (BuildContext context, int index) { child: new FlipWidget(
callbackTracker.add(index); left: new ListView.builder(
return new Container( itemBuilder: (BuildContext context, int index) {
key: new ValueKey<int>(index), callbackTracker.add(index);
height: 100.0, return new Container(
child: new Text("$index"), key: new ValueKey<int>(index),
); height: 100.0,
}, child: new Text("$index"),
);
},
),
right: const Text('Not Today'),
), ),
right: const Text('Not Today'),
); );
} }
...@@ -68,12 +71,15 @@ void main() { ...@@ -68,12 +71,15 @@ void main() {
}; };
Widget builder() { Widget builder() {
return new FlipWidget( return new Directionality(
left: new ListView.builder( textDirection: TextDirection.ltr,
controller: new ScrollController(initialScrollOffset: 300.0), child: new FlipWidget(
itemBuilder: itemBuilder, left: new ListView.builder(
controller: new ScrollController(initialScrollOffset: 300.0),
itemBuilder: itemBuilder,
),
right: const Text('Not Today'),
), ),
right: const Text('Not Today'),
); );
} }
...@@ -173,8 +179,11 @@ void main() { ...@@ -173,8 +179,11 @@ void main() {
} }
Widget builder() { Widget builder() {
return new ListView.builder( return new Directionality(
itemBuilder: itemBuilder, textDirection: TextDirection.ltr,
child: new ListView.builder(
itemBuilder: itemBuilder,
),
); );
} }
...@@ -214,12 +223,15 @@ void main() { ...@@ -214,12 +223,15 @@ void main() {
); );
await tester.pumpWidget( await tester.pumpWidget(
new StatefulBuilder( new Directionality(
builder: (BuildContext context, StateSetter setter) { textDirection: TextDirection.ltr,
setState = setter; child: new StatefulBuilder(
return new Theme(data: themeData, child: viewport); builder: (BuildContext context, StateSetter setter) {
} setState = setter;
) return new Theme(data: themeData, child: viewport);
},
),
),
); );
DecoratedBox widget = tester.firstWidget(find.byType(DecoratedBox)); DecoratedBox widget = tester.firstWidget(find.byType(DecoratedBox));
...@@ -249,9 +261,12 @@ void main() { ...@@ -249,9 +261,12 @@ void main() {
}; };
await tester.pumpWidget( await tester.pumpWidget(
new ListView.builder( new Directionality(
padding: const EdgeInsets.fromLTRB(7.0, 3.0, 5.0, 11.0), textDirection: TextDirection.ltr,
itemBuilder: itemBuilder, child: new ListView.builder(
padding: const EdgeInsets.fromLTRB(7.0, 3.0, 5.0, 11.0),
itemBuilder: itemBuilder,
),
), ),
); );
...@@ -262,14 +277,19 @@ void main() { ...@@ -262,14 +277,19 @@ void main() {
}); });
testWidgets('ListView underflow extents', (WidgetTester tester) async { testWidgets('ListView underflow extents', (WidgetTester tester) async {
await tester.pumpWidget(new ListView( await tester.pumpWidget(
addAutomaticKeepAlives: false, new Directionality(
children: <Widget>[ textDirection: TextDirection.ltr,
new Container(height: 100.0), child: new ListView(
new Container(height: 100.0), addAutomaticKeepAlives: false,
new Container(height: 100.0), children: <Widget>[
], new Container(height: 100.0),
)); new Container(height: 100.0),
new Container(height: 100.0),
],
),
),
);
final RenderSliverList list = tester.renderObject(find.byType(SliverList)); final RenderSliverList list = tester.renderObject(find.byType(SliverList));
...@@ -294,6 +314,7 @@ void main() { ...@@ -294,6 +314,7 @@ void main() {
' │ constraints: SliverConstraints(AxisDirection.down,\n' ' │ constraints: SliverConstraints(AxisDirection.down,\n'
' │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n' ' │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
' │ 0.0, remainingPaintExtent: 600.0, crossAxisExtent: 800.0,\n' ' │ 0.0, remainingPaintExtent: 600.0, crossAxisExtent: 800.0,\n'
' │ crossAxisDirection: AxisDirection.right,\n'
' │ viewportMainAxisExtent: 600.0)\n' ' │ viewportMainAxisExtent: 600.0)\n'
' │ geometry: SliverGeometry(scrollExtent: 300.0, paintExtent: 300.0,\n' ' │ geometry: SliverGeometry(scrollExtent: 300.0, paintExtent: 300.0,\n'
' │ maxPaintExtent: 300.0)\n' ' │ maxPaintExtent: 300.0)\n'
...@@ -453,7 +474,7 @@ void main() { ...@@ -453,7 +474,7 @@ void main() {
' parentData: <none> (can use size)\n' ' parentData: <none> (can use size)\n'
' constraints: BoxConstraints(w=800.0, h=100.0)\n' ' constraints: BoxConstraints(w=800.0, h=100.0)\n'
' size: Size(800.0, 100.0)\n' ' size: Size(800.0, 100.0)\n'
' additionalConstraints: BoxConstraints(biggest)\n', ' additionalConstraints: BoxConstraints(biggest)\n'
), ),
); );
......
...@@ -21,8 +21,11 @@ Widget buildCard(BuildContext context, int index) { ...@@ -21,8 +21,11 @@ Widget buildCard(BuildContext context, int index) {
} }
Widget buildFrame() { Widget buildFrame() {
return new ListView.builder( return new Directionality(
itemBuilder: buildCard, textDirection: TextDirection.ltr,
child: new ListView.builder(
itemBuilder: buildCard,
),
); );
} }
......
...@@ -10,10 +10,13 @@ void main() { ...@@ -10,10 +10,13 @@ void main() {
// Regression test for https://github.com/flutter/flutter/issues/9506 // Regression test for https://github.com/flutter/flutter/issues/9506
Widget buildFrame(int itemCount) { Widget buildFrame(int itemCount) {
return new ListView.builder( return new Directionality(
itemExtent: 200.0, textDirection: TextDirection.ltr,
itemCount: itemCount, child: new ListView.builder(
itemBuilder: (BuildContext context, int index) => new Text('item $index'), itemExtent: 200.0,
itemCount: itemCount,
itemBuilder: (BuildContext context, int index) => new Text('item $index'),
),
); );
} }
...@@ -34,14 +37,17 @@ void main() { ...@@ -34,14 +37,17 @@ void main() {
// Regression test for https://github.com/flutter/flutter/issues/9506 // Regression test for https://github.com/flutter/flutter/issues/9506
Widget buildFrame(int itemCount) { Widget buildFrame(int itemCount) {
return new ListView.builder( return new Directionality(
itemCount: itemCount, textDirection: TextDirection.ltr,
itemBuilder: (BuildContext context, int index) { child: new ListView.builder(
return new SizedBox( itemCount: itemCount,
height: 200.0, itemBuilder: (BuildContext context, int index) {
child: new Text('item $index'), return new SizedBox(
); height: 200.0,
}, child: new Text('item $index'),
);
},
),
); );
} }
......
...@@ -24,10 +24,13 @@ Future<Null> slowDrag(WidgetTester tester, Offset start, Offset offset) async { ...@@ -24,10 +24,13 @@ Future<Null> slowDrag(WidgetTester tester, Offset start, Offset offset) async {
void main() { void main() {
testWidgets('Overscroll indicator color', (WidgetTester tester) async { testWidgets('Overscroll indicator color', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
new CustomScrollView( new Directionality(
slivers: <Widget>[ textDirection: TextDirection.ltr,
const SliverToBoxAdapter(child: const SizedBox(height: 2000.0)), child: new CustomScrollView(
], slivers: <Widget>[
const SliverToBoxAdapter(child: const SizedBox(height: 2000.0)),
],
),
), ),
); );
final RenderObject painter = tester.renderObject(find.byType(CustomPaint)); final RenderObject painter = tester.renderObject(find.byType(CustomPaint));
...@@ -57,10 +60,13 @@ void main() { ...@@ -57,10 +60,13 @@ void main() {
testWidgets('Overscroll indicator changes side when you drag on the other side', (WidgetTester tester) async { testWidgets('Overscroll indicator changes side when you drag on the other side', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
new CustomScrollView( new Directionality(
slivers: <Widget>[ textDirection: TextDirection.ltr,
const SliverToBoxAdapter(child: const SizedBox(height: 2000.0)), child: new CustomScrollView(
], slivers: <Widget>[
const SliverToBoxAdapter(child: const SizedBox(height: 2000.0)),
],
),
), ),
); );
final RenderObject painter = tester.renderObject(find.byType(CustomPaint)); final RenderObject painter = tester.renderObject(find.byType(CustomPaint));
...@@ -92,10 +98,13 @@ void main() { ...@@ -92,10 +98,13 @@ void main() {
testWidgets('Overscroll indicator changes side when you shift sides', (WidgetTester tester) async { testWidgets('Overscroll indicator changes side when you shift sides', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
new CustomScrollView( new Directionality(
slivers: <Widget>[ textDirection: TextDirection.ltr,
const SliverToBoxAdapter(child: const SizedBox(height: 2000.0)), child: new CustomScrollView(
], slivers: <Widget>[
const SliverToBoxAdapter(child: const SizedBox(height: 2000.0)),
],
),
), ),
); );
final RenderObject painter = tester.renderObject(find.byType(CustomPaint)); final RenderObject painter = tester.renderObject(find.byType(CustomPaint));
...@@ -125,11 +134,14 @@ void main() { ...@@ -125,11 +134,14 @@ void main() {
group('Flipping direction of scrollable doesn\'t change overscroll behavior', () { group('Flipping direction of scrollable doesn\'t change overscroll behavior', () {
testWidgets('down', (WidgetTester tester) async { testWidgets('down', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
new CustomScrollView( new Directionality(
physics: const AlwaysScrollableScrollPhysics(), textDirection: TextDirection.ltr,
slivers: <Widget>[ child: new CustomScrollView(
const SliverToBoxAdapter(child: const SizedBox(height: 20.0)), physics: const AlwaysScrollableScrollPhysics(),
], slivers: <Widget>[
const SliverToBoxAdapter(child: const SizedBox(height: 20.0)),
],
),
), ),
); );
final RenderObject painter = tester.renderObject(find.byType(CustomPaint)); final RenderObject painter = tester.renderObject(find.byType(CustomPaint));
...@@ -142,12 +154,15 @@ void main() { ...@@ -142,12 +154,15 @@ void main() {
testWidgets('up', (WidgetTester tester) async { testWidgets('up', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
new CustomScrollView( new Directionality(
reverse: true, textDirection: TextDirection.ltr,
physics: const AlwaysScrollableScrollPhysics(), child: new CustomScrollView(
slivers: <Widget>[ reverse: true,
const SliverToBoxAdapter(child: const SizedBox(height: 20.0)), physics: const AlwaysScrollableScrollPhysics(),
], slivers: <Widget>[
const SliverToBoxAdapter(child: const SizedBox(height: 20.0)),
],
),
), ),
); );
final RenderObject painter = tester.renderObject(find.byType(CustomPaint)); final RenderObject painter = tester.renderObject(find.byType(CustomPaint));
...@@ -161,11 +176,14 @@ void main() { ...@@ -161,11 +176,14 @@ void main() {
testWidgets('Overscroll in both directions', (WidgetTester tester) async { testWidgets('Overscroll in both directions', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
new CustomScrollView( new Directionality(
physics: const AlwaysScrollableScrollPhysics(), textDirection: TextDirection.ltr,
slivers: <Widget>[ child: new CustomScrollView(
const SliverToBoxAdapter(child: const SizedBox(height: 20.0)), physics: const AlwaysScrollableScrollPhysics(),
], slivers: <Widget>[
const SliverToBoxAdapter(child: const SizedBox(height: 20.0)),
],
),
), ),
); );
final RenderObject painter = tester.renderObject(find.byType(CustomPaint)); final RenderObject painter = tester.renderObject(find.byType(CustomPaint));
...@@ -180,16 +198,18 @@ void main() { ...@@ -180,16 +198,18 @@ void main() {
}); });
testWidgets('Overscroll horizontally', (WidgetTester tester) async { testWidgets('Overscroll horizontally', (WidgetTester tester) async {
await tester.pumpWidget(new Directionality( await tester.pumpWidget(
textDirection: TextDirection.ltr, new Directionality(
child: new CustomScrollView( textDirection: TextDirection.ltr,
scrollDirection: Axis.horizontal, child: new CustomScrollView(
physics: const AlwaysScrollableScrollPhysics(), scrollDirection: Axis.horizontal,
slivers: <Widget>[ physics: const AlwaysScrollableScrollPhysics(),
const SliverToBoxAdapter(child: const SizedBox(height: 20.0)), slivers: <Widget>[
], const SliverToBoxAdapter(child: const SizedBox(height: 20.0)),
],
),
), ),
)); );
final RenderObject painter = tester.renderObject(find.byType(CustomPaint)); final RenderObject painter = tester.renderObject(find.byType(CustomPaint));
await slowDrag(tester, const Offset(200.0, 200.0), const Offset(5.0, 0.0)); await slowDrag(tester, const Offset(200.0, 200.0), const Offset(5.0, 0.0));
expect(painter, paints..rotate(angle: math.PI / 2.0)..circle()..saveRestore()); expect(painter, paints..rotate(angle: math.PI / 2.0)..circle()..saveRestore());
...@@ -227,39 +247,43 @@ void main() { ...@@ -227,39 +247,43 @@ void main() {
testWidgets('Changing settings', (WidgetTester tester) async { testWidgets('Changing settings', (WidgetTester tester) async {
RenderObject painter; RenderObject painter;
await tester.pumpWidget(new Directionality( await tester.pumpWidget(
textDirection: TextDirection.ltr, new Directionality(
child: new ScrollConfiguration( textDirection: TextDirection.ltr,
behavior: new TestScrollBehavior1(), child: new ScrollConfiguration(
child: new CustomScrollView( behavior: new TestScrollBehavior1(),
scrollDirection: Axis.horizontal, child: new CustomScrollView(
physics: const AlwaysScrollableScrollPhysics(), scrollDirection: Axis.horizontal,
reverse: true, physics: const AlwaysScrollableScrollPhysics(),
slivers: <Widget>[ reverse: true,
const SliverToBoxAdapter(child: const SizedBox(height: 20.0)), slivers: <Widget>[
], const SliverToBoxAdapter(child: const SizedBox(height: 20.0)),
],
),
), ),
), ),
)); );
painter = tester.renderObject(find.byType(CustomPaint)); painter = tester.renderObject(find.byType(CustomPaint));
await slowDrag(tester, const Offset(200.0, 200.0), const Offset(5.0, 0.0)); await slowDrag(tester, const Offset(200.0, 200.0), const Offset(5.0, 0.0));
expect(painter, paints..rotate(angle: math.PI / 2.0)..circle(color: const Color(0x0A00FF00))); expect(painter, paints..rotate(angle: math.PI / 2.0)..circle(color: const Color(0x0A00FF00)));
expect(painter, isNot(paints..circle()..circle())); expect(painter, isNot(paints..circle()..circle()));
await tester.pumpAndSettle(const Duration(seconds: 1)); await tester.pumpAndSettle(const Duration(seconds: 1));
await tester.pumpWidget(new Directionality( await tester.pumpWidget(
textDirection: TextDirection.ltr, new Directionality(
child: new ScrollConfiguration( textDirection: TextDirection.ltr,
behavior: new TestScrollBehavior2(), child: new ScrollConfiguration(
child: new CustomScrollView( behavior: new TestScrollBehavior2(),
scrollDirection: Axis.horizontal, child: new CustomScrollView(
physics: const AlwaysScrollableScrollPhysics(), scrollDirection: Axis.horizontal,
slivers: <Widget>[ physics: const AlwaysScrollableScrollPhysics(),
const SliverToBoxAdapter(child: const SizedBox(height: 20.0)), slivers: <Widget>[
], const SliverToBoxAdapter(child: const SizedBox(height: 20.0)),
],
),
), ),
), ),
)); );
painter = tester.renderObject(find.byType(CustomPaint)); painter = tester.renderObject(find.byType(CustomPaint));
await slowDrag(tester, const Offset(200.0, 200.0), const Offset(5.0, 0.0)); await slowDrag(tester, const Offset(200.0, 200.0), const Offset(5.0, 0.0));
expect(painter, paints..rotate(angle: math.PI / 2.0)..circle(color: const Color(0x0A0000FF))..saveRestore()); expect(painter, paints..rotate(angle: math.PI / 2.0)..circle(color: const Color(0x0A0000FF))..saveRestore());
......
...@@ -30,25 +30,30 @@ class ThePositiveNumbers extends StatelessWidget { ...@@ -30,25 +30,30 @@ class ThePositiveNumbers extends StatelessWidget {
Future<Null> performTest(WidgetTester tester, bool maintainState) async { Future<Null> performTest(WidgetTester tester, bool maintainState) async {
final GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>(); final GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
await tester.pumpWidget(new Navigator( await tester.pumpWidget(
key: navigatorKey, new Directionality(
onGenerateRoute: (RouteSettings settings) { textDirection: TextDirection.ltr,
if (settings.name == '/') { child: new Navigator(
return new MaterialPageRoute<Null>( key: navigatorKey,
settings: settings, onGenerateRoute: (RouteSettings settings) {
builder: (_) => new Container(child: const ThePositiveNumbers(from: 0)), if (settings.name == '/') {
maintainState: maintainState, return new MaterialPageRoute<Null>(
); settings: settings,
} else if (settings.name == '/second') { builder: (_) => new Container(child: const ThePositiveNumbers(from: 0)),
return new MaterialPageRoute<Null>( maintainState: maintainState,
settings: settings, );
builder: (_) => new Container(child: const ThePositiveNumbers(from: 10000)), } else if (settings.name == '/second') {
maintainState: maintainState, return new MaterialPageRoute<Null>(
); settings: settings,
} builder: (_) => new Container(child: const ThePositiveNumbers(from: 10000)),
return null; maintainState: maintainState,
} );
)); }
return null;
}
),
),
);
// we're 600 pixels high, each item is 100 pixels high, scroll position is // we're 600 pixels high, each item is 100 pixels high, scroll position is
// 110.0, so we should have 7 items, 1..7. // 110.0, so we should have 7 items, 1..7.
......
...@@ -195,16 +195,21 @@ void main() { ...@@ -195,16 +195,21 @@ void main() {
final StateMarkerState keyState = key.currentState; final StateMarkerState keyState = key.currentState;
keyState.marker = "marked"; keyState.marker = "marked";
await tester.pumpWidget(new ListView( await tester.pumpWidget(
itemExtent: 100.0, new Directionality(
children: <Widget>[ textDirection: TextDirection.ltr,
new Container( child: new ListView(
key: const Key('container'), itemExtent: 100.0,
height: 100.0, children: <Widget>[
child: new StateMarker(key: key), new Container(
key: const Key('container'),
height: 100.0,
child: new StateMarker(key: key),
),
],
), ),
], ),
)); );
expect(key.currentState, equals(keyState)); expect(key.currentState, equals(keyState));
expect(keyState.marker, equals("marked")); expect(keyState.marker, equals("marked"));
......
...@@ -7,11 +7,16 @@ import 'package:flutter/widgets.dart'; ...@@ -7,11 +7,16 @@ import 'package:flutter/widgets.dart';
void main() { void main() {
testWidgets('Scroll flings twice in a row does not crash', (WidgetTester tester) async { testWidgets('Scroll flings twice in a row does not crash', (WidgetTester tester) async {
await tester.pumpWidget(new ListView( await tester.pumpWidget(
children: <Widget>[ new Directionality(
new Container(height: 100000.0) textDirection: TextDirection.ltr,
] child: new ListView(
)); children: <Widget>[
new Container(height: 100000.0)
],
),
),
);
final ScrollableState scrollable = final ScrollableState scrollable =
tester.state<ScrollableState>(find.byType(Scrollable)); tester.state<ScrollableState>(find.byType(Scrollable));
......
...@@ -12,10 +12,15 @@ void main() { ...@@ -12,10 +12,15 @@ void main() {
for (int i = 0; i < 80; i++) for (int i = 0; i < 80; i++)
textWidgets.add(new Text('$i')); textWidgets.add(new Text('$i'));
final ScrollController controller = new ScrollController(); final ScrollController controller = new ScrollController();
await tester.pumpWidget(new ListView( await tester.pumpWidget(
children: textWidgets, new Directionality(
controller: controller, textDirection: TextDirection.ltr,
)); child: new ListView(
children: textWidgets,
controller: controller,
),
),
);
expectNoAnimation(); expectNoAnimation();
final double currentPosition = controller.position.pixels; final double currentPosition = controller.position.pixels;
...@@ -30,10 +35,15 @@ void main() { ...@@ -30,10 +35,15 @@ void main() {
for (int i = 0; i < 80; i++) for (int i = 0; i < 80; i++)
textWidgets.add(new Text('$i')); textWidgets.add(new Text('$i'));
final ScrollController controller = new ScrollController(); final ScrollController controller = new ScrollController();
await tester.pumpWidget(new ListView( await tester.pumpWidget(
children: textWidgets, new Directionality(
controller: controller, textDirection: TextDirection.ltr,
)); child: new ListView(
children: textWidgets,
controller: controller,
),
),
);
expectNoAnimation(); expectNoAnimation();
...@@ -51,10 +61,15 @@ void main() { ...@@ -51,10 +61,15 @@ void main() {
for (int i = 0; i < 80; i++) for (int i = 0; i < 80; i++)
textWidgets.add(new Text('$i')); textWidgets.add(new Text('$i'));
final ScrollController controller = new ScrollController(); final ScrollController controller = new ScrollController();
await tester.pumpWidget(new ListView( await tester.pumpWidget(
children: textWidgets, new Directionality(
controller: controller, textDirection: TextDirection.ltr,
)); child: new ListView(
children: textWidgets,
controller: controller,
),
),
);
expectNoAnimation(); expectNoAnimation();
......
...@@ -12,10 +12,15 @@ void main() { ...@@ -12,10 +12,15 @@ void main() {
final List<Widget> textWidgets = <Widget>[]; final List<Widget> textWidgets = <Widget>[];
for (int i = 0; i < 250; i++) for (int i = 0; i < 250; i++)
textWidgets.add(new Text('$i')); textWidgets.add(new Text('$i'));
await tester.pumpWidget(new FlipWidget( await tester.pumpWidget(
left: new ListView(children: textWidgets), new Directionality(
right: new Container() textDirection: TextDirection.ltr,
)); child: new FlipWidget(
left: new ListView(children: textWidgets),
right: new Container()
),
),
);
await tester.fling(find.byType(ListView), const Offset(0.0, -200.0), 1000.0); await tester.fling(find.byType(ListView), const Offset(0.0, -200.0), 1000.0);
await tester.pump(); await tester.pump();
......
...@@ -61,7 +61,12 @@ void main() { ...@@ -61,7 +61,12 @@ void main() {
final List<Widget> textWidgets = <Widget>[]; final List<Widget> textWidgets = <Widget>[];
for (int i = 0; i < 250; i += 1) for (int i = 0; i < 250; i += 1)
textWidgets.add(new GestureDetector(onTap: () { log.add('tap $i'); }, child: new Text('$i', style: testFont))); textWidgets.add(new GestureDetector(onTap: () { log.add('tap $i'); }, child: new Text('$i', style: testFont)));
await tester.pumpWidget(new ListView(children: textWidgets)); await tester.pumpWidget(
new Directionality(
textDirection: TextDirection.ltr,
child: new ListView(children: textWidgets)
),
);
expect(log, equals(<String>[])); expect(log, equals(<String>[]));
await tester.tap(find.byType(Scrollable)); await tester.tap(find.byType(Scrollable));
...@@ -84,7 +89,12 @@ void main() { ...@@ -84,7 +89,12 @@ void main() {
final List<Widget> textWidgets = <Widget>[]; final List<Widget> textWidgets = <Widget>[];
for (int i = 0; i < 250; i += 1) for (int i = 0; i < 250; i += 1)
textWidgets.add(new GestureDetector(onTap: () { log.add('tap $i'); }, child: new Text('$i', style: testFont))); textWidgets.add(new GestureDetector(onTap: () { log.add('tap $i'); }, child: new Text('$i', style: testFont)));
await tester.pumpWidget(new ListView(children: textWidgets)); await tester.pumpWidget(
new Directionality(
textDirection: TextDirection.ltr,
child: new ListView(children: textWidgets)
),
);
expect(log, equals(<String>[])); expect(log, equals(<String>[]));
await tester.tap(find.byType(Scrollable)); await tester.tap(find.byType(Scrollable));
......
...@@ -8,27 +8,35 @@ import 'package:flutter/rendering.dart'; ...@@ -8,27 +8,35 @@ import 'package:flutter/rendering.dart';
void main() { void main() {
testWidgets('GridView default control', (WidgetTester tester) async { testWidgets('GridView default control', (WidgetTester tester) async {
await tester.pumpWidget(new Center( await tester.pumpWidget(
child: new GridView.count( new Directionality(
crossAxisCount: 1, textDirection: TextDirection.ltr,
child: new Center(
child: new GridView.count(
crossAxisCount: 1,
),
),
), ),
)); );
}); });
// Tests https://github.com/flutter/flutter/issues/5522 // Tests https://github.com/flutter/flutter/issues/5522
testWidgets('GridView displays correct children with nonzero padding', (WidgetTester tester) async { testWidgets('GridView displays correct children with nonzero padding', (WidgetTester tester) async {
final EdgeInsets padding = const EdgeInsets.fromLTRB(0.0, 100.0, 0.0, 0.0); final EdgeInsets padding = const EdgeInsets.fromLTRB(0.0, 100.0, 0.0, 0.0);
final Widget testWidget = new Align( final Widget testWidget = new Directionality(
child: new SizedBox( textDirection: TextDirection.ltr,
height: 800.0, child: new Align(
width: 300.0, // forces the grid children to be 300..300 child: new SizedBox(
child: new GridView.count( height: 800.0,
crossAxisCount: 1, width: 300.0, // forces the grid children to be 300..300
padding: padding, child: new GridView.count(
children: new List<Widget>.generate(10, (int index) { crossAxisCount: 1,
return new Text('$index', key: new ValueKey<int>(index)); padding: padding,
}).toList(), children: new List<Widget>.generate(10, (int index) {
return new Text('$index', key: new ValueKey<int>(index));
}).toList(),
),
), ),
), ),
); );
...@@ -72,14 +80,17 @@ void main() { ...@@ -72,14 +80,17 @@ void main() {
testWidgets('GridView.count() fixed itemExtent, scroll to end, append, scroll', (WidgetTester tester) async { testWidgets('GridView.count() fixed itemExtent, scroll to end, append, scroll', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/9506 // Regression test for https://github.com/flutter/flutter/issues/9506
Widget buildFrame(int itemCount) { Widget buildFrame(int itemCount) {
return new GridView.count( return new Directionality(
crossAxisCount: itemCount, textDirection: TextDirection.ltr,
children: new List<Widget>.generate(itemCount, (int index) { child: new GridView.count(
return new SizedBox( crossAxisCount: itemCount,
height: 200.0, children: new List<Widget>.generate(itemCount, (int index) {
child: new Text('item $index'), return new SizedBox(
); height: 200.0,
}), child: new Text('item $index'),
);
}),
),
); );
} }
......
...@@ -15,7 +15,12 @@ void main() { ...@@ -15,7 +15,12 @@ void main() {
final List<Widget> textWidgets = <Widget>[]; final List<Widget> textWidgets = <Widget>[];
for (int i = 0; i < 80; i++) for (int i = 0; i < 80; i++)
textWidgets.add(new Text('$i')); textWidgets.add(new Text('$i'));
await tester.pumpWidget(new ListView(children: textWidgets)); await tester.pumpWidget(
new Directionality(
textDirection: TextDirection.ltr,
child: new ListView(children: textWidgets),
),
);
expect(semantics,includesNodeWith(actions: <SemanticsAction>[SemanticsAction.scrollUp])); expect(semantics,includesNodeWith(actions: <SemanticsAction>[SemanticsAction.scrollUp]));
...@@ -48,10 +53,15 @@ void main() { ...@@ -48,10 +53,15 @@ void main() {
initialScrollOffset: kItemHeight / 2, initialScrollOffset: kItemHeight / 2,
); );
await tester.pumpWidget(new ListView( await tester.pumpWidget(
controller: scrollController, new Directionality(
children: containers textDirection: TextDirection.ltr,
)); child: new ListView(
controller: scrollController,
children: containers,
),
),
);
expect(scrollController.offset, kItemHeight / 2); expect(scrollController.offset, kItemHeight / 2);
......
...@@ -146,16 +146,21 @@ void main() { ...@@ -146,16 +146,21 @@ void main() {
testWidgets('Nested scrollables have a null PrimaryScrollController', (WidgetTester tester) async { testWidgets('Nested scrollables have a null PrimaryScrollController', (WidgetTester tester) async {
const Key innerKey = const Key('inner'); const Key innerKey = const Key('inner');
final ScrollController primaryScrollController = new ScrollController(); final ScrollController primaryScrollController = new ScrollController();
await tester.pumpWidget(new PrimaryScrollController( await tester.pumpWidget(
controller: primaryScrollController, new Directionality(
child: new SingleChildScrollView( textDirection: TextDirection.ltr,
primary: true, child: new PrimaryScrollController(
child: new Container( controller: primaryScrollController,
constraints: const BoxConstraints(maxHeight: 200.0), child: new SingleChildScrollView(
child: new ListView(key: innerKey, primary: true), primary: true,
child: new Container(
constraints: const BoxConstraints(maxHeight: 200.0),
child: new ListView(key: innerKey, primary: true),
),
),
), ),
), ),
)); );
final Scrollable innerScrollable = tester.widget( final Scrollable innerScrollable = tester.widget(
find.descendant( find.descendant(
......
...@@ -9,11 +9,14 @@ void main() { ...@@ -9,11 +9,14 @@ void main() {
testWidgets('SliverFillRemaining - no siblings', (WidgetTester tester) async { testWidgets('SliverFillRemaining - no siblings', (WidgetTester tester) async {
final ScrollController controller = new ScrollController(); final ScrollController controller = new ScrollController();
await tester.pumpWidget( await tester.pumpWidget(
new CustomScrollView( new Directionality(
controller: controller, textDirection: TextDirection.ltr,
slivers: <Widget>[ child: new CustomScrollView(
new SliverFillRemaining(child: new Container()), controller: controller,
], slivers: <Widget>[
new SliverFillRemaining(child: new Container()),
],
),
), ),
); );
expect(tester.renderObject<RenderBox>(find.byType(Container)).size.height, equals(600.0)); expect(tester.renderObject<RenderBox>(find.byType(Container)).size.height, equals(600.0));
...@@ -34,12 +37,15 @@ void main() { ...@@ -34,12 +37,15 @@ void main() {
testWidgets('SliverFillRemaining - one sibling', (WidgetTester tester) async { testWidgets('SliverFillRemaining - one sibling', (WidgetTester tester) async {
final ScrollController controller = new ScrollController(); final ScrollController controller = new ScrollController();
await tester.pumpWidget( await tester.pumpWidget(
new CustomScrollView( new Directionality(
controller: controller, textDirection: TextDirection.ltr,
slivers: <Widget>[ child: new CustomScrollView(
const SliverToBoxAdapter(child: const SizedBox(height: 100.0)), controller: controller,
new SliverFillRemaining(child: new Container()), slivers: <Widget>[
], const SliverToBoxAdapter(child: const SizedBox(height: 100.0)),
new SliverFillRemaining(child: new Container()),
],
),
), ),
); );
expect(tester.renderObject<RenderBox>(find.byType(Container)).size.height, equals(500.0)); expect(tester.renderObject<RenderBox>(find.byType(Container)).size.height, equals(500.0));
......
...@@ -79,7 +79,12 @@ class FooScrollBehavior extends ScrollBehavior { ...@@ -79,7 +79,12 @@ class FooScrollBehavior extends ScrollBehavior {
void main() { void main() {
testWidgets('Can animate scroll after setState', (WidgetTester tester) async { testWidgets('Can animate scroll after setState', (WidgetTester tester) async {
await tester.pumpWidget(new Foo()); await tester.pumpWidget(
new Directionality(
textDirection: TextDirection.ltr,
child: new Foo(),
),
);
expect(tester.state<ScrollableState>(find.byType(Scrollable)).position.pixels, 0.0); expect(tester.state<ScrollableState>(find.byType(Scrollable)).position.pixels, 0.0);
await tester.tap(find.byType(GestureDetector).first); await tester.tap(find.byType(GestureDetector).first);
await tester.pumpAndSettle(); await tester.pumpAndSettle();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment