Skip to content

Commit cd74fce

Browse files
Report zero velocity at the end of a panning simulation (Resolves #43) (#44)
1 parent d5069a6 commit cd74fce

File tree

5 files changed

+151
-0
lines changed

5 files changed

+151
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Test project in a PR
2+
on: [pull_request]
3+
jobs:
4+
test_linux:
5+
runs-on: ubuntu-latest
6+
defaults:
7+
run:
8+
working-directory: .
9+
steps:
10+
# Checkout the PR branch
11+
- uses: actions/checkout@v3
12+
13+
# Setup Flutter environment
14+
- uses: subosito/flutter-action@v2
15+
with:
16+
channel: "stable"
17+
18+
# Download all the packages that the app uses
19+
- run: flutter pub get
20+
21+
# TODO: run static analysis here when we get to zero analysis warnings
22+
23+
# Run all tests
24+
- run: flutter test
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<component name="ProjectRunConfigurationManager">
2+
<configuration default="false" name="Minimal Viewport (debug)" type="FlutterRunConfigurationType" factoryName="Flutter">
3+
<option name="filePath" value="$PROJECT_DIR$/example/lib/main_minimal_viewport.dart" />
4+
<method v="2" />
5+
</configuration>
6+
</component>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:page_list_viewport/page_list_viewport.dart';
3+
4+
void main() {
5+
runApp(
6+
MaterialApp(
7+
home: _MinimalViewportDemo(),
8+
),
9+
);
10+
}
11+
12+
class _MinimalViewportDemo extends StatefulWidget {
13+
const _MinimalViewportDemo({Key? key}) : super(key: key);
14+
15+
@override
16+
State<_MinimalViewportDemo> createState() => _MinimalViewportDemoState();
17+
}
18+
19+
class _MinimalViewportDemoState extends State<_MinimalViewportDemo> with TickerProviderStateMixin {
20+
late final PageListViewportController _controller;
21+
22+
@override
23+
void initState() {
24+
super.initState();
25+
_controller = PageListViewportController(vsync: this);
26+
}
27+
28+
@override
29+
void dispose() {
30+
_controller.dispose();
31+
super.dispose();
32+
}
33+
34+
@override
35+
Widget build(BuildContext context) {
36+
return Scaffold(
37+
body: PageListViewportGestures(
38+
controller: _controller,
39+
child: PageListViewport(
40+
controller: _controller,
41+
pageCount: 10,
42+
naturalPageSize: const Size(8.5, 11) * 72,
43+
builder: (context, index) {
44+
return DecoratedBox(
45+
decoration: BoxDecoration(
46+
color: Colors.white,
47+
border: Border.all(color: Colors.grey),
48+
),
49+
);
50+
},
51+
),
52+
),
53+
);
54+
}
55+
}

lib/src/page_list_viewport.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,11 @@ class PageListViewportController extends OrientationController {
632632
// Check if the simulation is close enough to complete for us to stop it.
633633
if ((_origin - _previousOrigin).distance.abs() < 0.01) {
634634
stopSimulation();
635+
636+
// Ensure that we always report a zero velocity at the end of the simulation.
637+
_acceleration = Offset.zero;
638+
_velocity = Offset.zero;
639+
_scaleVelocity = 0;
635640
}
636641

637642
// Update our previous-frame accounting, for the next simulation frame.

test/panning_simulation_test.dart

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_test/flutter_test.dart';
3+
import 'package:page_list_viewport/page_list_viewport.dart';
4+
5+
void main() {
6+
group("Panning simulation", () {
7+
testWidgets("reports zero velocity when it completes", (widgetTester) async {
8+
final controller = PageListViewportController(vsync: widgetTester);
9+
await _pumpPageListViewport(widgetTester, controller: controller);
10+
11+
Offset? latestVelocity;
12+
controller.addListener(() {
13+
latestVelocity = controller.velocity;
14+
});
15+
16+
// Fling up, to scroll down, and run a panning simulation.
17+
await widgetTester.fling(find.byType(Scaffold), const Offset(0, -500), 4000);
18+
await widgetTester.pumpAndSettle();
19+
20+
// Ensure that the final reported velocity is zero.
21+
expect(latestVelocity, isNotNull);
22+
expect(latestVelocity, Offset.zero);
23+
});
24+
});
25+
}
26+
27+
Future<void> _pumpPageListViewport(
28+
WidgetTester tester, {
29+
PageListViewportController? controller,
30+
int pageCount = 10,
31+
Size? naturalPageSize,
32+
PageBuilder? pageBuilder,
33+
}) async {
34+
controller ??= PageListViewportController(vsync: tester);
35+
naturalPageSize ??= const Size(8.5, 11) * 72;
36+
pageBuilder ??= _defaultPageBuilder;
37+
38+
await tester.pumpWidget(
39+
MaterialApp(
40+
home: Scaffold(
41+
body: PageListViewportGestures(
42+
controller: controller,
43+
child: PageListViewport(
44+
controller: controller,
45+
pageCount: pageCount,
46+
naturalPageSize: naturalPageSize,
47+
builder: pageBuilder,
48+
),
49+
),
50+
),
51+
),
52+
);
53+
54+
await tester.pumpAndSettle();
55+
}
56+
57+
Widget _defaultPageBuilder(BuildContext context, int pageIndex) {
58+
return const ColoredBox(
59+
color: Colors.white,
60+
);
61+
}

0 commit comments

Comments
 (0)