mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
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.
This commit is contained in:
parent
474c2c7df6
commit
6ddd0bb4b8
@ -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 })
|
||||
);
|
||||
}
|
||||
|
||||
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),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('SingleChildScollView ensureVisible Axis.vertical', (WidgetTester tester) async {
|
||||
BuildContext findContext(int i) => tester.element(findKey(i));
|
||||
|
||||
await tester.pumpWidget(buildSingleChildScrollView(Axis.vertical));
|
||||
group('SingleChildScollView', () {
|
||||
testWidgets('SingleChildScollView ensureVisible Axis.vertical', (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.vertical));
|
||||
|
||||
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.getTopLeft(findKey(3)).y, equals(100.0));
|
||||
|
||||
Scrollable2.ensureVisible(findContext(4), alignment: 1.0);
|
||||
await tester.pump();
|
||||
expect(tester.getBottomRight(findKey(4)).y, equals(500.0));
|
||||
Scrollable2.ensureVisible(findContext(6));
|
||||
await tester.pump();
|
||||
expect(tester.getTopLeft(findKey(6)).y, 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(4), alignment: 1.0);
|
||||
await tester.pump();
|
||||
expect(tester.getBottomRight(findKey(4)).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.getTopLeft(findKey(3)).y, equals(100.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));
|
||||
|
||||
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(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));
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('SingleChildScollView ensureVisible Axis.horizontal', (WidgetTester tester) async {
|
||||
BuildContext findContext(int i) => tester.element(findKey(i));
|
||||
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(buildSingleChildScrollView(Axis.horizontal));
|
||||
await tester.pumpWidget(buildListView(Axis.vertical));
|
||||
|
||||
Scrollable2.ensureVisible(findContext(3));
|
||||
await tester.pump();
|
||||
expect(tester.getTopLeft(findKey(3)).x, equals(100.0));
|
||||
await prepare(480.0);
|
||||
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)).x, equals(500.0));
|
||||
await prepare(1083.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)).x, equals(700.0));
|
||||
await prepare(735.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)).x, equals(100.0));
|
||||
await prepare(123.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)).x, 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('SingleChildScollView ensureVisible Axis.vertical reverse', (WidgetTester tester) async {
|
||||
BuildContext findContext(int i) => tester.element(findKey(i));
|
||||
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(buildSingleChildScrollView(Axis.vertical, reverse: true));
|
||||
await tester.pumpWidget(buildListView(Axis.horizontal));
|
||||
|
||||
Scrollable2.ensureVisible(findContext(3));
|
||||
await tester.pump();
|
||||
expect(tester.getBottomRight(findKey(3)).y, equals(500.0));
|
||||
await prepare(23.0);
|
||||
Scrollable2.ensureVisible(findContext(3));
|
||||
await tester.pump();
|
||||
expect(tester.getTopLeft(findKey(3)).x, equals(100.0));
|
||||
|
||||
Scrollable2.ensureVisible(findContext(0));
|
||||
await tester.pump();
|
||||
expect(tester.getBottomRight(findKey(0)).y, equals(300.0));
|
||||
await prepare(843.0);
|
||||
Scrollable2.ensureVisible(findContext(6));
|
||||
await tester.pump();
|
||||
expect(tester.getTopLeft(findKey(6)).x, equals(500.0));
|
||||
|
||||
Scrollable2.ensureVisible(findContext(2), alignment: 1.0);
|
||||
await tester.pump();
|
||||
expect(tester.getTopLeft(findKey(2)).y, equals(100.0));
|
||||
await prepare(415.0);
|
||||
Scrollable2.ensureVisible(findContext(4), alignment: 1.0);
|
||||
await tester.pump();
|
||||
expect(tester.getBottomRight(findKey(4)).x, equals(700.0));
|
||||
|
||||
Scrollable2.ensureVisible(findContext(6), alignment: 1.0);
|
||||
await tester.pump();
|
||||
expect(tester.getBottomRight(findKey(6)).y, equals(500.0));
|
||||
await prepare(46.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.getBottomRight(findKey(3)).y, equals(500.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('SingleChildScollView ensureVisible Axis.horizontal', (WidgetTester tester) async {
|
||||
BuildContext findContext(int i) => tester.element(findKey(i));
|
||||
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(buildSingleChildScrollView(Axis.horizontal, reverse: true));
|
||||
await tester.pumpWidget(buildListView(Axis.vertical, reverse: true));
|
||||
|
||||
Scrollable2.ensureVisible(findContext(3));
|
||||
await tester.pump();
|
||||
expect(tester.getBottomRight(findKey(3)).x, equals(700.0));
|
||||
await prepare(211.0);
|
||||
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)).x, equals(300.0));
|
||||
await prepare(23.0);
|
||||
Scrollable2.ensureVisible(findContext(0));
|
||||
await tester.pump();
|
||||
expect(tester.getBottomRight(findKey(0)).y, equals(500.0));
|
||||
|
||||
Scrollable2.ensureVisible(findContext(2), alignment: 1.0);
|
||||
await tester.pump();
|
||||
expect(tester.getTopLeft(findKey(2)).x, equals(100.0));
|
||||
await prepare(230.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)).x, equals(700.0));
|
||||
await prepare(1083.0);
|
||||
Scrollable2.ensureVisible(findContext(6), alignment: 1.0);
|
||||
await tester.pump();
|
||||
expect(tester.getBottomRight(findKey(6)).y, equals(300.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));
|
||||
});
|
||||
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('SingleChildScollView ensureVisible rotated child', (WidgetTester tester) async {
|
||||
BuildContext findContext(int i) => tester.element(findKey(i));
|
||||
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(
|
||||
new Center(
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user