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