Commit 6ddd0bb4 authored by Adam Barth's avatar Adam Barth Committed by GitHub

Make ensureVisible work with sliver-based viewports (#7920)

There appears to be an issue with children before the center widget.
I've filled a bug about that issue and will follow up in a later patch.
parent 474c2c7d
......@@ -1117,7 +1117,7 @@ abstract class RenderAbstractViewport implements RenderObject {
return null;
}
double getOffsetToReveal(RenderObject descendant, double alignment);
double getOffsetToReveal(RenderObject target, double alignment);
}
// ///
......@@ -1339,9 +1339,83 @@ abstract class RenderViewportBase2<ParentDataClass extends ContainerParentDataMi
}
@override
double getOffsetToReveal(RenderObject descendant, double alignment) {
// TODO(abath): Implement this function for sliver-based viewports.
return 0.0;
double getOffsetToReveal(RenderObject target, double alignment) {
double leadingScrollOffset;
double targetMainAxisExtent;
RenderObject descendant;
if (target is RenderBox) {
final RenderBox targetBox = target;
RenderBox pivot = targetBox;
while (pivot.parent is RenderBox)
pivot = pivot.parent;
assert(pivot.parent != null);
assert(pivot.parent != this);
assert(pivot != this);
final Matrix4 transform = targetBox.getTransformTo(pivot);
final Rect bounds = MatrixUtils.transformRect(transform, targetBox.paintBounds);
target = pivot;
// TODO(abarth): Support other kinds of render objects besides slivers.
assert(target.parent is RenderSliver);
final RenderSliver pivotParent = target.parent;
final GrowthDirection growthDirection = pivotParent.constraints.growthDirection;
switch (applyGrowthDirectionToAxisDirection(axisDirection, growthDirection)) {
case AxisDirection.up:
leadingScrollOffset = pivot.size.height - bounds.bottom;
targetMainAxisExtent = bounds.height;
break;
case AxisDirection.right:
leadingScrollOffset = bounds.left;
targetMainAxisExtent = bounds.width;
break;
case AxisDirection.down:
leadingScrollOffset = bounds.top;
targetMainAxisExtent = bounds.height;
break;
case AxisDirection.left:
leadingScrollOffset = pivot.size.width - bounds.right;
targetMainAxisExtent = bounds.width;
break;
}
descendant = pivot;
} else if (target is RenderSliver) {
final RenderSliver targetSliver = target;
leadingScrollOffset = 0.0;
targetMainAxisExtent = targetSliver.geometry.scrollExtent;
descendant = targetSliver;
} else {
return offset.pixels;
}
// The child will be the topmost object before we get to the viewport.
RenderObject child = descendant;
while (child.parent is RenderSliver) {
final RenderSliver parent = child.parent;
leadingScrollOffset += parent.childScrollOffset(child);
child = parent;
}
assert(child.parent == this);
assert(child is RenderSliver);
final RenderSliver sliver = child;
leadingScrollOffset = scrollOffsetOf(sliver, leadingScrollOffset);
double mainAxisExtent;
switch (axis) {
case Axis.horizontal:
mainAxisExtent = size.width;
break;
case Axis.vertical:
mainAxisExtent = size.height;
break;
}
return leadingScrollOffset - (mainAxisExtent - targetMainAxisExtent) * alignment;
}
@protected
......@@ -1408,6 +1482,9 @@ abstract class RenderViewportBase2<ParentDataClass extends ContainerParentDataMi
@protected
Offset paintOffsetOf(RenderSliver child);
@protected
double scrollOffsetOf(RenderSliver child, double scrollOffset);
// applyPaintTransform
/// Converts the `parentMainAxisPosition` into the child's coordinate system.
......@@ -1692,6 +1769,32 @@ class RenderViewport2 extends RenderViewportBase2<SliverPhysicalContainerParentD
return childParentData.paintOffset;
}
@override
double scrollOffsetOf(RenderSliver child, double scrollOffsetWithinChild) {
assert(child.parent == this);
final GrowthDirection growthDirection = child.constraints.growthDirection;
assert(growthDirection != null);
switch (growthDirection) {
case GrowthDirection.forward:
double scrollOffsetToChild = 0.0;
RenderSliver current = center;
while (current != child) {
scrollOffsetToChild += current.geometry.scrollExtent;
current = childAfter(current);
}
return scrollOffsetToChild + scrollOffsetWithinChild;
case GrowthDirection.reverse:
double scrollOffsetToChild = 0.0;
RenderSliver current = childBefore(center);
while (current != child) {
scrollOffsetToChild -= current.geometry.scrollExtent;
current = childBefore(current);
}
return scrollOffsetToChild - scrollOffsetWithinChild;
}
return null;
}
@override
void applyPaintTransform(RenderObject child, Matrix4 transform) {
assert(child != null);
......@@ -1949,6 +2052,19 @@ class RenderShrinkWrappingViewport extends RenderViewportBase2<SliverLogicalCont
return computeAbsolutePaintOffset(child, childParentData.layoutOffset, GrowthDirection.forward);
}
@override
double scrollOffsetOf(RenderSliver child, double scrollOffsetWithinChild) {
assert(child.parent == this);
assert(child.constraints.growthDirection == GrowthDirection.forward);
double scrollOffsetToChild = 0.0;
RenderSliver current = firstChild;
while (current != child) {
scrollOffsetToChild += current.geometry.scrollExtent;
current = childAfter(current);
}
return scrollOffsetToChild + scrollOffsetWithinChild;
}
@override
void applyPaintTransform(RenderObject child, Matrix4 transform) {
assert(child != null);
......
......@@ -199,7 +199,6 @@ class _RenderSingleChildViewport extends RenderBox with RenderObjectWithChildMix
return null;
}
double get _minScrollExtent {
assert(hasSize);
return 0.0;
......@@ -334,44 +333,43 @@ class _RenderSingleChildViewport extends RenderBox with RenderObjectWithChildMix
}
@override
double getOffsetToReveal(RenderObject descendant, double alignment) {
if (descendant is! RenderBox)
double getOffsetToReveal(RenderObject target, double alignment) {
if (target is! RenderBox)
return offset.pixels;
final RenderBox target = descendant;
final Matrix4 transform = target.getTransformTo(this);
final Rect bounds = MatrixUtils.transformRect(transform, target.paintBounds);
final RenderBox targetBox = target;
final Matrix4 transform = targetBox.getTransformTo(this);
final Rect bounds = MatrixUtils.transformRect(transform, targetBox.paintBounds);
final Size contentSize = child.size;
double leading;
double trailing;
double viewportExtent;
double leadingScrollOffset;
double targetMainAxisExtent;
double mainAxisExtent;
assert(axisDirection != null);
switch (axisDirection) {
case AxisDirection.up:
viewportExtent = size.height;
leading = contentSize.height - bounds.bottom;
trailing = contentSize.height - bounds.top;
mainAxisExtent = size.height;
leadingScrollOffset = contentSize.height - bounds.bottom;
targetMainAxisExtent = bounds.height;
break;
case AxisDirection.right:
viewportExtent = size.width;
leading = bounds.left;
trailing = bounds.right;
mainAxisExtent = size.width;
leadingScrollOffset = bounds.left;
targetMainAxisExtent = bounds.width;
break;
case AxisDirection.down:
viewportExtent = size.height;
leading = bounds.top;
trailing = bounds.bottom;
mainAxisExtent = size.height;
leadingScrollOffset = bounds.top;
targetMainAxisExtent = bounds.height;
break;
case AxisDirection.left:
viewportExtent = size.width;
leading = contentSize.width - bounds.right;
trailing = contentSize.width - bounds.left;
mainAxisExtent = size.width;
leadingScrollOffset = contentSize.width - bounds.right;
targetMainAxisExtent = bounds.width;
break;
}
final double targetExtent = trailing - leading;
return leading - (viewportExtent - targetExtent) * alignment;
return leadingScrollOffset - (mainAxisExtent - targetMainAxisExtent) * alignment;
}
}
......@@ -5,6 +5,7 @@
import 'dart:math' as math;
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
Finder findKey(int i) => find.byKey(new ValueKey<int>(i));
......@@ -34,125 +35,402 @@ Widget buildSingleChildScrollView(Axis scrollDirection, { bool reverse: false })
);
}
void main() {
testWidgets('SingleChildScollView ensureVisible Axis.vertical', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
await tester.pumpWidget(buildSingleChildScrollView(Axis.vertical));
Scrollable2.ensureVisible(findContext(3));
await tester.pump();
expect(tester.getTopLeft(findKey(3)).y, equals(100.0));
Scrollable2.ensureVisible(findContext(6));
await tester.pump();
expect(tester.getTopLeft(findKey(6)).y, equals(300.0));
Scrollable2.ensureVisible(findContext(4), alignment: 1.0);
await tester.pump();
expect(tester.getBottomRight(findKey(4)).y, equals(500.0));
Scrollable2.ensureVisible(findContext(0), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(0)).y, equals(100.0));
Scrollable2.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
await tester.pump();
await tester.pump(const Duration(milliseconds: 1020));
expect(tester.getTopLeft(findKey(3)).y, equals(100.0));
});
testWidgets('SingleChildScollView ensureVisible Axis.horizontal', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
await tester.pumpWidget(buildSingleChildScrollView(Axis.horizontal));
Scrollable2.ensureVisible(findContext(3));
await tester.pump();
expect(tester.getTopLeft(findKey(3)).x, equals(100.0));
Scrollable2.ensureVisible(findContext(6));
await tester.pump();
expect(tester.getTopLeft(findKey(6)).x, equals(500.0));
Scrollable2.ensureVisible(findContext(4), alignment: 1.0);
await tester.pump();
expect(tester.getBottomRight(findKey(4)).x, equals(700.0));
Scrollable2.ensureVisible(findContext(0), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(0)).x, equals(100.0));
Scrollable2.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
await tester.pump();
await tester.pump(const Duration(milliseconds: 1020));
expect(tester.getTopLeft(findKey(3)).x, equals(100.0));
});
testWidgets('SingleChildScollView ensureVisible Axis.vertical reverse', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
await tester.pumpWidget(buildSingleChildScrollView(Axis.vertical, reverse: true));
Scrollable2.ensureVisible(findContext(3));
await tester.pump();
expect(tester.getBottomRight(findKey(3)).y, equals(500.0));
Scrollable2.ensureVisible(findContext(0));
await tester.pump();
expect(tester.getBottomRight(findKey(0)).y, equals(300.0));
Widget buildListView(Axis scrollDirection, { bool reverse: false, bool shrinkWrap: false }) {
return new Center(
child: new SizedBox(
width: 600.0,
height: 400.0,
child: new ListView(
scrollDirection: scrollDirection,
reverse: reverse,
shrinkWrap: shrinkWrap,
children: <Widget>[
new Container(key: new ValueKey<int>(0), width: 200.0, height: 200.0),
new Container(key: new ValueKey<int>(1), width: 200.0, height: 200.0),
new Container(key: new ValueKey<int>(2), width: 200.0, height: 200.0),
new Container(key: new ValueKey<int>(3), width: 200.0, height: 200.0),
new Container(key: new ValueKey<int>(4), width: 200.0, height: 200.0),
new Container(key: new ValueKey<int>(5), width: 200.0, height: 200.0),
new Container(key: new ValueKey<int>(6), width: 200.0, height: 200.0),
],
),
),
);
}
Scrollable2.ensureVisible(findContext(2), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(2)).y, equals(100.0));
void main() {
Scrollable2.ensureVisible(findContext(6), alignment: 1.0);
await tester.pump();
expect(tester.getBottomRight(findKey(6)).y, equals(500.0));
group('SingleChildScollView', () {
testWidgets('SingleChildScollView ensureVisible Axis.vertical', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
Scrollable2.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
await tester.pump();
await tester.pump(const Duration(milliseconds: 1020));
expect(tester.getBottomRight(findKey(3)).y, equals(500.0));
});
await tester.pumpWidget(buildSingleChildScrollView(Axis.vertical));
testWidgets('SingleChildScollView ensureVisible Axis.horizontal', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
Scrollable2.ensureVisible(findContext(3));
await tester.pump();
expect(tester.getTopLeft(findKey(3)).y, equals(100.0));
await tester.pumpWidget(buildSingleChildScrollView(Axis.horizontal, reverse: true));
Scrollable2.ensureVisible(findContext(6));
await tester.pump();
expect(tester.getTopLeft(findKey(6)).y, equals(300.0));
Scrollable2.ensureVisible(findContext(3));
await tester.pump();
expect(tester.getBottomRight(findKey(3)).x, equals(700.0));
Scrollable2.ensureVisible(findContext(4), alignment: 1.0);
await tester.pump();
expect(tester.getBottomRight(findKey(4)).y, equals(500.0));
Scrollable2.ensureVisible(findContext(0));
await tester.pump();
expect(tester.getBottomRight(findKey(0)).x, equals(300.0));
Scrollable2.ensureVisible(findContext(0), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(0)).y, equals(100.0));
Scrollable2.ensureVisible(findContext(2), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(2)).x, equals(100.0));
Scrollable2.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
await tester.pump();
await tester.pump(const Duration(milliseconds: 1020));
expect(tester.getTopLeft(findKey(3)).y, equals(100.0));
});
testWidgets('SingleChildScollView ensureVisible Axis.horizontal', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
await tester.pumpWidget(buildSingleChildScrollView(Axis.horizontal));
Scrollable2.ensureVisible(findContext(3));
await tester.pump();
expect(tester.getTopLeft(findKey(3)).x, equals(100.0));
Scrollable2.ensureVisible(findContext(6));
await tester.pump();
expect(tester.getTopLeft(findKey(6)).x, equals(500.0));
Scrollable2.ensureVisible(findContext(4), alignment: 1.0);
await tester.pump();
expect(tester.getBottomRight(findKey(4)).x, equals(700.0));
Scrollable2.ensureVisible(findContext(0), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(0)).x, equals(100.0));
Scrollable2.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
await tester.pump();
await tester.pump(const Duration(milliseconds: 1020));
expect(tester.getTopLeft(findKey(3)).x, equals(100.0));
});
testWidgets('SingleChildScollView ensureVisible Axis.vertical reverse', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
await tester.pumpWidget(buildSingleChildScrollView(Axis.vertical, reverse: true));
Scrollable2.ensureVisible(findContext(3));
await tester.pump();
expect(tester.getBottomRight(findKey(3)).y, equals(500.0));
Scrollable2.ensureVisible(findContext(0));
await tester.pump();
expect(tester.getBottomRight(findKey(0)).y, equals(300.0));
Scrollable2.ensureVisible(findContext(2), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(2)).y, equals(100.0));
Scrollable2.ensureVisible(findContext(6), alignment: 1.0);
await tester.pump();
expect(tester.getBottomRight(findKey(6)).y, equals(500.0));
Scrollable2.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
await tester.pump();
await tester.pump(const Duration(milliseconds: 1020));
expect(tester.getBottomRight(findKey(3)).y, equals(500.0));
});
testWidgets('SingleChildScollView ensureVisible Axis.horizontal reverse', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
await tester.pumpWidget(buildSingleChildScrollView(Axis.horizontal, reverse: true));
Scrollable2.ensureVisible(findContext(3));
await tester.pump();
expect(tester.getBottomRight(findKey(3)).x, equals(700.0));
Scrollable2.ensureVisible(findContext(0));
await tester.pump();
expect(tester.getBottomRight(findKey(0)).x, equals(300.0));
Scrollable2.ensureVisible(findContext(2), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(2)).x, equals(100.0));
Scrollable2.ensureVisible(findContext(6), alignment: 1.0);
await tester.pump();
expect(tester.getBottomRight(findKey(6)).x, equals(700.0));
Scrollable2.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
await tester.pump();
await tester.pump(const Duration(milliseconds: 1020));
expect(tester.getBottomRight(findKey(3)).x, equals(700.0));
});
testWidgets('SingleChildScollView ensureVisible rotated child', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
await tester.pumpWidget(
new Center(
child: new SizedBox(
width: 600.0,
height: 400.0,
child: new SingleChildScrollView(
child: new BlockBody(
children: <Widget>[
new Container(height: 200.0),
new Container(height: 200.0),
new Container(height: 200.0),
new Container(
height: 200.0,
child: new Center(
child: new Transform(
transform: new Matrix4.rotationZ(math.PI),
child: new Container(
key: new ValueKey<int>(0),
width: 100.0,
height: 100.0,
decoration: const BoxDecoration(
backgroundColor: const Color(0xFFFFFFFF),
),
),
),
),
),
new Container(height: 200.0),
new Container(height: 200.0),
new Container(height: 200.0),
],
),
),
),
)
);
Scrollable2.ensureVisible(findContext(6), alignment: 1.0);
await tester.pump();
expect(tester.getBottomRight(findKey(6)).x, equals(700.0));
Scrollable2.ensureVisible(findContext(0));
await tester.pump();
expect(tester.getBottomRight(findKey(0)).y, closeTo(100.0, 0.1));
Scrollable2.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
await tester.pump();
await tester.pump(const Duration(milliseconds: 1020));
expect(tester.getBottomRight(findKey(3)).x, equals(700.0));
Scrollable2.ensureVisible(findContext(0), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(0)).y, closeTo(500.0, 0.1));
});
});
testWidgets('SingleChildScollView ensureVisible rotated child', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
await tester.pumpWidget(
new Center(
group('ListView', () {
testWidgets('ListView ensureVisible Axis.vertical', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
Future<Null> prepare(double offset) async {
tester.state<Scrollable2State>(find.byType(Scrollable2)).position.jumpTo(offset);
await tester.pump();
}
await tester.pumpWidget(buildListView(Axis.vertical));
await prepare(480.0);
Scrollable2.ensureVisible(findContext(3));
await tester.pump();
expect(tester.getTopLeft(findKey(3)).y, equals(100.0));
await prepare(1083.0);
Scrollable2.ensureVisible(findContext(6));
await tester.pump();
expect(tester.getTopLeft(findKey(6)).y, equals(300.0));
await prepare(735.0);
Scrollable2.ensureVisible(findContext(4), alignment: 1.0);
await tester.pump();
expect(tester.getBottomRight(findKey(4)).y, equals(500.0));
await prepare(123.0);
Scrollable2.ensureVisible(findContext(0), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(0)).y, equals(100.0));
await prepare(523.0);
Scrollable2.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
await tester.pump();
await tester.pump(const Duration(milliseconds: 1020));
expect(tester.getTopLeft(findKey(3)).y, equals(100.0));
});
testWidgets('ListView ensureVisible Axis.horizontal', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
Future<Null> prepare(double offset) async {
tester.state<Scrollable2State>(find.byType(Scrollable2)).position.jumpTo(offset);
await tester.pump();
}
await tester.pumpWidget(buildListView(Axis.horizontal));
await prepare(23.0);
Scrollable2.ensureVisible(findContext(3));
await tester.pump();
expect(tester.getTopLeft(findKey(3)).x, equals(100.0));
await prepare(843.0);
Scrollable2.ensureVisible(findContext(6));
await tester.pump();
expect(tester.getTopLeft(findKey(6)).x, equals(500.0));
await prepare(415.0);
Scrollable2.ensureVisible(findContext(4), alignment: 1.0);
await tester.pump();
expect(tester.getBottomRight(findKey(4)).x, equals(700.0));
await prepare(46.0);
Scrollable2.ensureVisible(findContext(0), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(0)).x, equals(100.0));
await prepare(211.0);
Scrollable2.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
await tester.pump();
await tester.pump(const Duration(milliseconds: 1020));
expect(tester.getTopLeft(findKey(3)).x, equals(100.0));
});
testWidgets('ListView ensureVisible Axis.vertical reverse', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
Future<Null> prepare(double offset) async {
tester.state<Scrollable2State>(find.byType(Scrollable2)).position.jumpTo(offset);
await tester.pump();
}
await tester.pumpWidget(buildListView(Axis.vertical, reverse: true));
await prepare(211.0);
Scrollable2.ensureVisible(findContext(3));
await tester.pump();
expect(tester.getBottomRight(findKey(3)).y, equals(500.0));
await prepare(23.0);
Scrollable2.ensureVisible(findContext(0));
await tester.pump();
expect(tester.getBottomRight(findKey(0)).y, equals(500.0));
await prepare(230.0);
Scrollable2.ensureVisible(findContext(2), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(2)).y, equals(100.0));
await prepare(1083.0);
Scrollable2.ensureVisible(findContext(6), alignment: 1.0);
await tester.pump();
expect(tester.getBottomRight(findKey(6)).y, equals(300.0));
await prepare(345.0);
Scrollable2.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
await tester.pump();
await tester.pump(const Duration(milliseconds: 1020));
expect(tester.getBottomRight(findKey(3)).y, equals(500.0));
});
testWidgets('ListView ensureVisible Axis.horizontal reverse', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
Future<Null> prepare(double offset) async {
tester.state<Scrollable2State>(find.byType(Scrollable2)).position.jumpTo(offset);
await tester.pump();
}
await tester.pumpWidget(buildListView(Axis.horizontal, reverse: true));
await prepare(211.0);
Scrollable2.ensureVisible(findContext(3));
await tester.pump();
expect(tester.getBottomRight(findKey(3)).x, equals(700.0));
await prepare(23.0);
Scrollable2.ensureVisible(findContext(0));
await tester.pump();
expect(tester.getBottomRight(findKey(0)).x, equals(700.0));
await prepare(230.0);
Scrollable2.ensureVisible(findContext(2), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(2)).x, equals(100.0));
await prepare(1083.0);
Scrollable2.ensureVisible(findContext(6), alignment: 1.0);
await tester.pump();
expect(tester.getBottomRight(findKey(6)).x, equals(300.0));
await prepare(345.0);
Scrollable2.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
await tester.pump();
await tester.pump(const Duration(milliseconds: 1020));
expect(tester.getBottomRight(findKey(3)).x, equals(700.0));
});
// TODO(abarth): Unskip this test. See https://github.com/flutter/flutter/issues/7919
testWidgets('ListView ensureVisible negative child', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
Future<Null> prepare(double offset) async {
tester.state<Scrollable2State>(find.byType(Scrollable2)).position.jumpTo(offset);
await tester.pump();
}
double getOffset() {
return tester.state<Scrollable2State>(find.byType(Scrollable2)).position.pixels;
}
Widget buildSliver(int i) {
return new SliverToBoxAdapter(
key: new ValueKey<int>(i),
child: new Container(width: 200.0, height: 200.0),
);
}
await tester.pumpWidget(new Center(
child: new SizedBox(
width: 600.0,
height: 400.0,
child: new SingleChildScrollView(
child: new BlockBody(
child: new Scrollable2(
viewportBuilder: (BuildContext context, ViewportOffset offset) {
return new Viewport2(
offset: offset,
center: new ValueKey<int>(4),
slivers: <Widget>[
buildSliver(0),
buildSliver(1),
buildSliver(2),
buildSliver(3),
buildSliver(4),
buildSliver(5),
buildSliver(6),
],
);
},
),
),
));
await prepare(-125.0);
Scrollable2.ensureVisible(findContext(3));
await tester.pump();
expect(getOffset(), equals(-200.0));
await prepare(-225.0);
Scrollable2.ensureVisible(findContext(2));
await tester.pump();
expect(getOffset(), equals(-400.0));
}, skip: true);
testWidgets('ListView ensureVisible rotated child', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
Future<Null> prepare(double offset) async {
tester.state<Scrollable2State>(find.byType(Scrollable2)).position.jumpTo(offset);
await tester.pump();
}
await tester.pumpWidget(
new Center(
child: new SizedBox(
width: 600.0,
height: 400.0,
child: new ListView(
children: <Widget>[
new Container(height: 200.0),
new Container(height: 200.0),
......@@ -179,17 +457,163 @@ void main() {
],
),
),
),
)
);
Scrollable2.ensureVisible(findContext(0));
await tester.pump();
expect(tester.getBottomRight(findKey(0)).y, closeTo(100.0, 0.1));
Scrollable2.ensureVisible(findContext(0), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(0)).y, closeTo(500.0, 0.1));
)
);
await prepare(321.0);
Scrollable2.ensureVisible(findContext(0));
await tester.pump();
expect(tester.getBottomRight(findKey(0)).y, closeTo(100.0, 0.1));
Scrollable2.ensureVisible(findContext(0), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(0)).y, closeTo(500.0, 0.1));
});
});
group('ListView shrinkWrap', () {
testWidgets('ListView ensureVisible Axis.vertical', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
Future<Null> prepare(double offset) async {
tester.state<Scrollable2State>(find.byType(Scrollable2)).position.jumpTo(offset);
await tester.pump();
}
await tester.pumpWidget(buildListView(Axis.vertical, shrinkWrap: true));
await prepare(480.0);
Scrollable2.ensureVisible(findContext(3));
await tester.pump();
expect(tester.getTopLeft(findKey(3)).y, equals(100.0));
await prepare(1083.0);
Scrollable2.ensureVisible(findContext(6));
await tester.pump();
expect(tester.getTopLeft(findKey(6)).y, equals(300.0));
await prepare(735.0);
Scrollable2.ensureVisible(findContext(4), alignment: 1.0);
await tester.pump();
expect(tester.getBottomRight(findKey(4)).y, equals(500.0));
await prepare(123.0);
Scrollable2.ensureVisible(findContext(0), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(0)).y, equals(100.0));
await prepare(523.0);
Scrollable2.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
await tester.pump();
await tester.pump(const Duration(milliseconds: 1020));
expect(tester.getTopLeft(findKey(3)).y, equals(100.0));
});
testWidgets('ListView ensureVisible Axis.horizontal', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
Future<Null> prepare(double offset) async {
tester.state<Scrollable2State>(find.byType(Scrollable2)).position.jumpTo(offset);
await tester.pump();
}
await tester.pumpWidget(buildListView(Axis.horizontal, shrinkWrap: true));
await prepare(23.0);
Scrollable2.ensureVisible(findContext(3));
await tester.pump();
expect(tester.getTopLeft(findKey(3)).x, equals(100.0));
await prepare(843.0);
Scrollable2.ensureVisible(findContext(6));
await tester.pump();
expect(tester.getTopLeft(findKey(6)).x, equals(500.0));
await prepare(415.0);
Scrollable2.ensureVisible(findContext(4), alignment: 1.0);
await tester.pump();
expect(tester.getBottomRight(findKey(4)).x, equals(700.0));
await prepare(46.0);
Scrollable2.ensureVisible(findContext(0), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(0)).x, equals(100.0));
await prepare(211.0);
Scrollable2.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
await tester.pump();
await tester.pump(const Duration(milliseconds: 1020));
expect(tester.getTopLeft(findKey(3)).x, equals(100.0));
});
testWidgets('ListView ensureVisible Axis.vertical reverse', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
Future<Null> prepare(double offset) async {
tester.state<Scrollable2State>(find.byType(Scrollable2)).position.jumpTo(offset);
await tester.pump();
}
await tester.pumpWidget(buildListView(Axis.vertical, reverse: true, shrinkWrap: true));
await prepare(211.0);
Scrollable2.ensureVisible(findContext(3));
await tester.pump();
expect(tester.getBottomRight(findKey(3)).y, equals(500.0));
await prepare(23.0);
Scrollable2.ensureVisible(findContext(0));
await tester.pump();
expect(tester.getBottomRight(findKey(0)).y, equals(500.0));
await prepare(230.0);
Scrollable2.ensureVisible(findContext(2), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(2)).y, equals(100.0));
await prepare(1083.0);
Scrollable2.ensureVisible(findContext(6), alignment: 1.0);
await tester.pump();
expect(tester.getBottomRight(findKey(6)).y, equals(300.0));
await prepare(345.0);
Scrollable2.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
await tester.pump();
await tester.pump(const Duration(milliseconds: 1020));
expect(tester.getBottomRight(findKey(3)).y, equals(500.0));
});
testWidgets('ListView ensureVisible Axis.horizontal reverse', (WidgetTester tester) async {
BuildContext findContext(int i) => tester.element(findKey(i));
Future<Null> prepare(double offset) async {
tester.state<Scrollable2State>(find.byType(Scrollable2)).position.jumpTo(offset);
await tester.pump();
}
await tester.pumpWidget(buildListView(Axis.horizontal, reverse: true, shrinkWrap: true));
await prepare(211.0);
Scrollable2.ensureVisible(findContext(3));
await tester.pump();
expect(tester.getBottomRight(findKey(3)).x, equals(700.0));
await prepare(23.0);
Scrollable2.ensureVisible(findContext(0));
await tester.pump();
expect(tester.getBottomRight(findKey(0)).x, equals(700.0));
await prepare(230.0);
Scrollable2.ensureVisible(findContext(2), alignment: 1.0);
await tester.pump();
expect(tester.getTopLeft(findKey(2)).x, equals(100.0));
await prepare(1083.0);
Scrollable2.ensureVisible(findContext(6), alignment: 1.0);
await tester.pump();
expect(tester.getBottomRight(findKey(6)).x, equals(300.0));
await prepare(345.0);
Scrollable2.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
await tester.pump();
await tester.pump(const Duration(milliseconds: 1020));
expect(tester.getBottomRight(findKey(3)).x, equals(700.0));
});
});
}
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