564 lines
21 KiB
Dart
564 lines
21 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// This file contains a wacky demonstration of creating a custom ScrollPosition
|
|
// setup. It's testing that we don't regress the factoring of the
|
|
// ScrollPosition/ScrollActivity logic into a state where you can no longer
|
|
// implement this, e.g. by oversimplifying it or overfitting it to the features
|
|
// built into the framework itself.
|
|
|
|
import 'dart:collection';
|
|
import 'dart:math' as math;
|
|
|
|
import 'package:flutter/rendering.dart';
|
|
import 'package:flutter/gestures.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
class LinkedScrollController extends ScrollController {
|
|
LinkedScrollController({ this.before, this.after });
|
|
|
|
LinkedScrollController? before;
|
|
LinkedScrollController? after;
|
|
|
|
ScrollController? _parent;
|
|
|
|
void setParent(ScrollController? newParent) {
|
|
if (_parent != null) {
|
|
positions.forEach(_parent!.detach);
|
|
}
|
|
_parent = newParent;
|
|
if (_parent != null) {
|
|
positions.forEach(_parent!.attach);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void attach(ScrollPosition position) {
|
|
assert(position is LinkedScrollPosition, 'A LinkedScrollController must only be used with LinkedScrollPositions.');
|
|
final LinkedScrollPosition linkedPosition = position as LinkedScrollPosition;
|
|
assert(linkedPosition.owner == this, 'A LinkedScrollPosition cannot change controllers once created.');
|
|
super.attach(position);
|
|
_parent?.attach(position);
|
|
}
|
|
|
|
@override
|
|
void detach(ScrollPosition position) {
|
|
super.detach(position);
|
|
_parent?.detach(position);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
if (_parent != null) {
|
|
positions.forEach(_parent!.detach);
|
|
}
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
LinkedScrollPosition createScrollPosition(ScrollPhysics physics, ScrollContext context, ScrollPosition? oldPosition) {
|
|
return LinkedScrollPosition(
|
|
this,
|
|
physics: physics,
|
|
context: context,
|
|
initialPixels: initialScrollOffset,
|
|
oldPosition: oldPosition,
|
|
);
|
|
}
|
|
|
|
bool get canLinkWithBefore => before != null && before!.hasClients;
|
|
|
|
bool get canLinkWithAfter => after != null && after!.hasClients;
|
|
|
|
Iterable<LinkedScrollActivity> linkWithBefore(LinkedScrollPosition driver) {
|
|
assert(canLinkWithBefore);
|
|
return before!.link(driver);
|
|
}
|
|
|
|
Iterable<LinkedScrollActivity> linkWithAfter(LinkedScrollPosition driver) {
|
|
assert(canLinkWithAfter);
|
|
return after!.link(driver);
|
|
}
|
|
|
|
Iterable<LinkedScrollActivity> link(LinkedScrollPosition driver) sync* {
|
|
assert(hasClients);
|
|
for (final LinkedScrollPosition position in positions.cast<LinkedScrollPosition>())
|
|
yield position.link(driver);
|
|
}
|
|
|
|
@override
|
|
void debugFillDescription(List<String> description) {
|
|
super.debugFillDescription(description);
|
|
if (before != null && after != null) {
|
|
description.add('links: ⬌');
|
|
} else if (before != null) {
|
|
description.add('links: ⬅');
|
|
} else if (after != null) {
|
|
description.add('links: ➡');
|
|
} else {
|
|
description.add('links: none');
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
class LinkedScrollPosition extends ScrollPositionWithSingleContext {
|
|
LinkedScrollPosition(
|
|
this.owner, {
|
|
required ScrollPhysics physics,
|
|
required ScrollContext context,
|
|
required double initialPixels,
|
|
ScrollPosition? oldPosition,
|
|
}) : assert(owner != null),
|
|
super(
|
|
physics: physics,
|
|
context: context,
|
|
initialPixels: initialPixels,
|
|
oldPosition: oldPosition,
|
|
);
|
|
|
|
final LinkedScrollController owner;
|
|
|
|
Set<LinkedScrollActivity>? _beforeActivities;
|
|
Set<LinkedScrollActivity>? _afterActivities;
|
|
|
|
@override
|
|
void beginActivity(ScrollActivity? newActivity) {
|
|
if (newActivity == null)
|
|
return;
|
|
if (_beforeActivities != null) {
|
|
for (final LinkedScrollActivity activity in _beforeActivities!)
|
|
activity.unlink(this);
|
|
_beforeActivities!.clear();
|
|
}
|
|
if (_afterActivities != null) {
|
|
for (final LinkedScrollActivity activity in _afterActivities!)
|
|
activity.unlink(this);
|
|
_afterActivities!.clear();
|
|
}
|
|
super.beginActivity(newActivity);
|
|
}
|
|
|
|
@override
|
|
void applyUserOffset(double delta) {
|
|
updateUserScrollDirection(delta > 0.0 ? ScrollDirection.forward : ScrollDirection.reverse);
|
|
final double value = pixels - physics.applyPhysicsToUserOffset(this, delta);
|
|
|
|
if (value == pixels)
|
|
return;
|
|
|
|
double beforeOverscroll = 0.0;
|
|
if (owner.canLinkWithBefore && (value < minScrollExtent)) {
|
|
final double delta = value - minScrollExtent;
|
|
_beforeActivities ??= HashSet<LinkedScrollActivity>();
|
|
_beforeActivities!.addAll(owner.linkWithBefore(this));
|
|
for (final LinkedScrollActivity activity in _beforeActivities!)
|
|
beforeOverscroll = math.min(activity.moveBy(delta), beforeOverscroll);
|
|
assert(beforeOverscroll <= 0.0);
|
|
}
|
|
|
|
double afterOverscroll = 0.0;
|
|
if (owner.canLinkWithAfter && (value > maxScrollExtent)) {
|
|
final double delta = value - maxScrollExtent;
|
|
_afterActivities ??= HashSet<LinkedScrollActivity>();
|
|
_afterActivities!.addAll(owner.linkWithAfter(this));
|
|
for (final LinkedScrollActivity activity in _afterActivities!)
|
|
afterOverscroll = math.max(activity.moveBy(delta), afterOverscroll);
|
|
assert(afterOverscroll >= 0.0);
|
|
}
|
|
|
|
assert(beforeOverscroll == 0.0 || afterOverscroll == 0.0);
|
|
|
|
final double localOverscroll = setPixels(value.clamp(
|
|
owner.canLinkWithBefore ? minScrollExtent : -double.infinity,
|
|
owner.canLinkWithAfter ? maxScrollExtent : double.infinity,
|
|
));
|
|
|
|
assert(localOverscroll == 0.0 || (beforeOverscroll == 0.0 && afterOverscroll == 0.0));
|
|
}
|
|
|
|
void _userMoved(ScrollDirection direction) {
|
|
updateUserScrollDirection(direction);
|
|
}
|
|
|
|
LinkedScrollActivity link(LinkedScrollPosition driver) {
|
|
if (this.activity is! LinkedScrollActivity)
|
|
beginActivity(LinkedScrollActivity(this));
|
|
final LinkedScrollActivity? activity = this.activity as LinkedScrollActivity?;
|
|
activity!.link(driver);
|
|
return activity;
|
|
}
|
|
|
|
void unlink(LinkedScrollActivity activity) {
|
|
if (_beforeActivities != null)
|
|
_beforeActivities!.remove(activity);
|
|
if (_afterActivities != null)
|
|
_afterActivities!.remove(activity);
|
|
}
|
|
|
|
@override
|
|
void debugFillDescription(List<String> description) {
|
|
super.debugFillDescription(description);
|
|
description.add('owner: $owner');
|
|
}
|
|
}
|
|
|
|
class LinkedScrollActivity extends ScrollActivity {
|
|
LinkedScrollActivity(
|
|
LinkedScrollPosition delegate,
|
|
) : super(delegate);
|
|
|
|
@override
|
|
LinkedScrollPosition get delegate => super.delegate as LinkedScrollPosition;
|
|
|
|
final Set<LinkedScrollPosition> drivers = HashSet<LinkedScrollPosition>();
|
|
|
|
void link(LinkedScrollPosition driver) {
|
|
drivers.add(driver);
|
|
}
|
|
|
|
void unlink(LinkedScrollPosition driver) {
|
|
drivers.remove(driver);
|
|
if (drivers.isEmpty)
|
|
delegate.goIdle();
|
|
}
|
|
|
|
@override
|
|
bool get shouldIgnorePointer => true;
|
|
|
|
@override
|
|
bool get isScrolling => true;
|
|
|
|
// LinkedScrollActivity is not self-driven but moved by calls to the [moveBy]
|
|
// method.
|
|
@override
|
|
double get velocity => 0.0;
|
|
|
|
double moveBy(double delta) {
|
|
assert(drivers.isNotEmpty);
|
|
ScrollDirection? commonDirection;
|
|
for (final LinkedScrollPosition driver in drivers) {
|
|
commonDirection ??= driver.userScrollDirection;
|
|
if (driver.userScrollDirection != commonDirection)
|
|
commonDirection = ScrollDirection.idle;
|
|
}
|
|
|
|
if (commonDirection != null) {
|
|
delegate._userMoved(commonDirection);
|
|
}
|
|
return delegate.setPixels(delegate.pixels + delta);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
for (final LinkedScrollPosition driver in drivers)
|
|
driver.unlink(this);
|
|
super.dispose();
|
|
}
|
|
}
|
|
|
|
class Test extends StatefulWidget {
|
|
const Test({ Key? key }) : super(key: key);
|
|
@override
|
|
_TestState createState() => _TestState();
|
|
}
|
|
|
|
class _TestState extends State<Test> {
|
|
late LinkedScrollController _beforeController;
|
|
late LinkedScrollController _afterController;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_beforeController = LinkedScrollController();
|
|
_afterController = LinkedScrollController(before: _beforeController);
|
|
_beforeController.after = _afterController;
|
|
}
|
|
|
|
@override
|
|
void didChangeDependencies() {
|
|
super.didChangeDependencies();
|
|
_beforeController.setParent(PrimaryScrollController.of(context));
|
|
_afterController.setParent(PrimaryScrollController.of(context));
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_beforeController.dispose();
|
|
_afterController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Column(
|
|
children: <Widget>[
|
|
Expanded(
|
|
child: ListView(
|
|
controller: _beforeController,
|
|
children: <Widget>[
|
|
Container(
|
|
margin: const EdgeInsets.all(8.0),
|
|
padding: const EdgeInsets.all(8.0),
|
|
height: 250.0,
|
|
color: const Color(0xFF90F090),
|
|
child: const Center(child: Text('Hello A')),
|
|
),
|
|
Container(
|
|
margin: const EdgeInsets.all(8.0),
|
|
padding: const EdgeInsets.all(8.0),
|
|
height: 250.0,
|
|
color: const Color(0xFF90F090),
|
|
child: const Center(child: Text('Hello B')),
|
|
),
|
|
Container(
|
|
margin: const EdgeInsets.all(8.0),
|
|
padding: const EdgeInsets.all(8.0),
|
|
height: 250.0,
|
|
color: const Color(0xFF90F090),
|
|
child: const Center(child: Text('Hello C')),
|
|
),
|
|
Container(
|
|
margin: const EdgeInsets.all(8.0),
|
|
padding: const EdgeInsets.all(8.0),
|
|
height: 250.0,
|
|
color: const Color(0xFF90F090),
|
|
child: const Center(child: Text('Hello D')),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const Divider(),
|
|
Expanded(
|
|
child: ListView(
|
|
controller: _afterController,
|
|
children: <Widget>[
|
|
Container(
|
|
margin: const EdgeInsets.all(8.0),
|
|
padding: const EdgeInsets.all(8.0),
|
|
height: 250.0,
|
|
color: const Color(0xFF9090F0),
|
|
child: const Center(child: Text('Hello 1')),
|
|
),
|
|
Container(
|
|
margin: const EdgeInsets.all(8.0),
|
|
padding: const EdgeInsets.all(8.0),
|
|
height: 250.0,
|
|
color: const Color(0xFF9090F0),
|
|
child: const Center(child: Text('Hello 2')),
|
|
),
|
|
Container(
|
|
margin: const EdgeInsets.all(8.0),
|
|
padding: const EdgeInsets.all(8.0),
|
|
height: 250.0,
|
|
color: const Color(0xFF9090F0),
|
|
child: const Center(child: Text('Hello 3')),
|
|
),
|
|
Container(
|
|
margin: const EdgeInsets.all(8.0),
|
|
padding: const EdgeInsets.all(8.0),
|
|
height: 250.0,
|
|
color: const Color(0xFF9090F0),
|
|
child: const Center(child: Text('Hello 4')),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
testWidgets('LinkedScrollController - 1', (WidgetTester tester) async {
|
|
await tester.pumpWidget(const Test());
|
|
expect(find.text('Hello A'), findsOneWidget);
|
|
expect(find.text('Hello 1'), findsOneWidget);
|
|
expect(find.text('Hello D'), findsNothing);
|
|
expect(find.text('Hello 4'), findsNothing);
|
|
await tester.pump(const Duration(seconds: 2));
|
|
await tester.fling(find.text('Hello A'), const Offset(0.0, -50.0), 10000.0);
|
|
await tester.pumpAndSettle();
|
|
await tester.pump(const Duration(seconds: 2));
|
|
expect(find.text('Hello A'), findsNothing);
|
|
expect(find.text('Hello 1'), findsOneWidget);
|
|
expect(find.text('Hello D'), findsOneWidget);
|
|
expect(find.text('Hello 4'), findsNothing);
|
|
await tester.pump(const Duration(seconds: 2));
|
|
await tester.drag(find.text('Hello D'), const Offset(0.0, -10000.0));
|
|
await tester.pump(const Duration(seconds: 2));
|
|
expect(find.text('Hello A'), findsNothing);
|
|
expect(find.text('Hello 1'), findsNothing);
|
|
expect(find.text('Hello D'), findsOneWidget);
|
|
expect(find.text('Hello 4'), findsOneWidget);
|
|
await tester.pump(const Duration(seconds: 2));
|
|
await tester.drag(find.text('Hello D'), const Offset(0.0, -10000.0));
|
|
await tester.pump(const Duration(seconds: 2));
|
|
expect(find.text('Hello A'), findsNothing);
|
|
expect(find.text('Hello 1'), findsNothing);
|
|
expect(find.text('Hello D'), findsOneWidget);
|
|
expect(find.text('Hello 4'), findsOneWidget);
|
|
await tester.pump(const Duration(seconds: 2));
|
|
await tester.drag(find.text('Hello 4'), const Offset(0.0, -10000.0));
|
|
await tester.pump(const Duration(seconds: 2));
|
|
expect(find.text('Hello A'), findsNothing);
|
|
expect(find.text('Hello 1'), findsNothing);
|
|
expect(find.text('Hello D'), findsOneWidget);
|
|
expect(find.text('Hello 4'), findsOneWidget);
|
|
await tester.pump(const Duration(seconds: 2));
|
|
await tester.drag(find.text('Hello D'), const Offset(0.0, 10000.0));
|
|
await tester.pump(const Duration(seconds: 2));
|
|
expect(find.text('Hello A'), findsOneWidget);
|
|
expect(find.text('Hello 1'), findsNothing);
|
|
expect(find.text('Hello D'), findsNothing);
|
|
expect(find.text('Hello 4'), findsOneWidget);
|
|
await tester.pump(const Duration(seconds: 2));
|
|
await tester.drag(find.text('Hello A'), const Offset(0.0, 10000.0));
|
|
await tester.pump(const Duration(seconds: 2));
|
|
expect(find.text('Hello A'), findsOneWidget);
|
|
expect(find.text('Hello 1'), findsNothing);
|
|
expect(find.text('Hello D'), findsNothing);
|
|
expect(find.text('Hello 4'), findsOneWidget);
|
|
await tester.pump(const Duration(seconds: 2));
|
|
await tester.drag(find.text('Hello A'), const Offset(0.0, -10000.0));
|
|
await tester.pump(const Duration(seconds: 2));
|
|
expect(find.text('Hello A'), findsNothing);
|
|
expect(find.text('Hello 1'), findsNothing);
|
|
expect(find.text('Hello D'), findsOneWidget);
|
|
expect(find.text('Hello 4'), findsOneWidget);
|
|
await tester.pump(const Duration(seconds: 2));
|
|
await tester.drag(find.text('Hello 4'), const Offset(0.0, 10000.0));
|
|
await tester.pump(const Duration(seconds: 2));
|
|
expect(find.text('Hello A'), findsOneWidget);
|
|
expect(find.text('Hello 1'), findsOneWidget);
|
|
expect(find.text('Hello D'), findsNothing);
|
|
expect(find.text('Hello 4'), findsNothing);
|
|
await tester.pump(const Duration(seconds: 2));
|
|
await tester.drag(find.text('Hello 1'), const Offset(0.0, 10000.0));
|
|
await tester.pump(const Duration(seconds: 2));
|
|
expect(find.text('Hello A'), findsOneWidget);
|
|
expect(find.text('Hello 1'), findsOneWidget);
|
|
expect(find.text('Hello D'), findsNothing);
|
|
expect(find.text('Hello 4'), findsNothing);
|
|
await tester.pump(const Duration(seconds: 2));
|
|
await tester.drag(find.text('Hello 1'), const Offset(0.0, -10000.0));
|
|
await tester.pump(const Duration(seconds: 2));
|
|
expect(find.text('Hello A'), findsOneWidget);
|
|
expect(find.text('Hello 1'), findsNothing);
|
|
expect(find.text('Hello D'), findsNothing);
|
|
expect(find.text('Hello 4'), findsOneWidget);
|
|
});
|
|
testWidgets('LinkedScrollController - 2', (WidgetTester tester) async {
|
|
await tester.pumpWidget(const Test());
|
|
expect(find.text('Hello A'), findsOneWidget);
|
|
expect(find.text('Hello B'), findsOneWidget);
|
|
expect(find.text('Hello C'), findsNothing);
|
|
expect(find.text('Hello D'), findsNothing);
|
|
expect(find.text('Hello 1'), findsOneWidget);
|
|
expect(find.text('Hello 2'), findsOneWidget);
|
|
expect(find.text('Hello 3'), findsNothing);
|
|
expect(find.text('Hello 4'), findsNothing);
|
|
final TestGesture gestureTop = await tester.startGesture(const Offset(200.0, 150.0));
|
|
final TestGesture gestureBottom = await tester.startGesture(const Offset(600.0, 450.0));
|
|
await tester.pump(const Duration(seconds: 1));
|
|
await gestureTop.moveBy(const Offset(0.0, -270.0));
|
|
await tester.pump(const Duration(seconds: 1));
|
|
expect(find.text('Hello A'), findsNothing);
|
|
expect(find.text('Hello B'), findsOneWidget);
|
|
expect(find.text('Hello C'), findsOneWidget);
|
|
expect(find.text('Hello D'), findsNothing);
|
|
expect(find.text('Hello 1'), findsOneWidget);
|
|
expect(find.text('Hello 2'), findsOneWidget);
|
|
expect(find.text('Hello 3'), findsNothing);
|
|
expect(find.text('Hello 4'), findsNothing);
|
|
await gestureBottom.moveBy(const Offset(0.0, -270.0));
|
|
await tester.pump(const Duration(seconds: 1));
|
|
expect(find.text('Hello A'), findsNothing);
|
|
expect(find.text('Hello B'), findsOneWidget);
|
|
expect(find.text('Hello C'), findsOneWidget);
|
|
expect(find.text('Hello D'), findsNothing);
|
|
expect(find.text('Hello 1'), findsNothing);
|
|
expect(find.text('Hello 2'), findsOneWidget);
|
|
expect(find.text('Hello 3'), findsOneWidget);
|
|
expect(find.text('Hello 4'), findsNothing);
|
|
await gestureTop.moveBy(const Offset(0.0, -270.0));
|
|
await gestureBottom.moveBy(const Offset(0.0, -270.0));
|
|
await tester.pump(const Duration(seconds: 1));
|
|
expect(find.text('Hello A'), findsNothing);
|
|
expect(find.text('Hello B'), findsNothing);
|
|
expect(find.text('Hello C'), findsOneWidget);
|
|
expect(find.text('Hello D'), findsOneWidget);
|
|
expect(find.text('Hello 1'), findsNothing);
|
|
expect(find.text('Hello 2'), findsNothing);
|
|
expect(find.text('Hello 3'), findsOneWidget);
|
|
expect(find.text('Hello 4'), findsOneWidget);
|
|
await gestureTop.moveBy(const Offset(0.0, 270.0));
|
|
await gestureBottom.moveBy(const Offset(0.0, 270.0));
|
|
await tester.pump(const Duration(seconds: 1));
|
|
expect(find.text('Hello A'), findsNothing);
|
|
expect(find.text('Hello B'), findsOneWidget);
|
|
expect(find.text('Hello C'), findsOneWidget);
|
|
expect(find.text('Hello D'), findsNothing);
|
|
expect(find.text('Hello 1'), findsNothing);
|
|
expect(find.text('Hello 2'), findsOneWidget);
|
|
expect(find.text('Hello 3'), findsOneWidget);
|
|
expect(find.text('Hello 4'), findsNothing);
|
|
await gestureBottom.moveBy(const Offset(0.0, 270.0));
|
|
await tester.pump(const Duration(seconds: 1));
|
|
expect(find.text('Hello A'), findsNothing);
|
|
expect(find.text('Hello B'), findsOneWidget);
|
|
expect(find.text('Hello C'), findsOneWidget);
|
|
expect(find.text('Hello D'), findsNothing);
|
|
expect(find.text('Hello 1'), findsOneWidget);
|
|
expect(find.text('Hello 2'), findsOneWidget);
|
|
expect(find.text('Hello 3'), findsNothing);
|
|
expect(find.text('Hello 4'), findsNothing);
|
|
await gestureBottom.moveBy(const Offset(0.0, 50.0));
|
|
await tester.pump(const Duration(seconds: 1));
|
|
expect(find.text('Hello A'), findsOneWidget);
|
|
expect(find.text('Hello B'), findsOneWidget);
|
|
expect(find.text('Hello C'), findsNothing);
|
|
expect(find.text('Hello D'), findsNothing);
|
|
expect(find.text('Hello 1'), findsOneWidget);
|
|
expect(find.text('Hello 2'), findsOneWidget);
|
|
expect(find.text('Hello 3'), findsNothing);
|
|
expect(find.text('Hello 4'), findsNothing);
|
|
await gestureBottom.moveBy(const Offset(0.0, 50.0));
|
|
await tester.pump(const Duration(seconds: 1));
|
|
expect(find.text('Hello A'), findsOneWidget);
|
|
expect(find.text('Hello B'), findsOneWidget);
|
|
expect(find.text('Hello C'), findsNothing);
|
|
expect(find.text('Hello D'), findsNothing);
|
|
expect(find.text('Hello 1'), findsOneWidget);
|
|
expect(find.text('Hello 2'), findsOneWidget);
|
|
expect(find.text('Hello 3'), findsNothing);
|
|
expect(find.text('Hello 4'), findsNothing);
|
|
await gestureBottom.moveBy(const Offset(0.0, 50.0));
|
|
await tester.pump(const Duration(seconds: 1));
|
|
expect(find.text('Hello A'), findsOneWidget);
|
|
expect(find.text('Hello B'), findsOneWidget);
|
|
expect(find.text('Hello C'), findsNothing);
|
|
expect(find.text('Hello D'), findsNothing);
|
|
expect(find.text('Hello 1'), findsOneWidget);
|
|
expect(find.text('Hello 2'), findsOneWidget);
|
|
expect(find.text('Hello 3'), findsNothing);
|
|
expect(find.text('Hello 4'), findsNothing);
|
|
await gestureTop.moveBy(const Offset(0.0, -270.0));
|
|
expect(find.text('Hello A'), findsOneWidget);
|
|
expect(find.text('Hello B'), findsOneWidget);
|
|
expect(find.text('Hello C'), findsNothing);
|
|
expect(find.text('Hello D'), findsNothing);
|
|
expect(find.text('Hello 1'), findsOneWidget);
|
|
expect(find.text('Hello 2'), findsOneWidget);
|
|
expect(find.text('Hello 3'), findsNothing);
|
|
expect(find.text('Hello 4'), findsNothing);
|
|
await tester.pump(const Duration(seconds: 1));
|
|
await tester.pump(const Duration(seconds: 60));
|
|
});
|
|
}
|