Skip to content

Commit 87829c5

Browse files
Add viewport origin velocity tracking (Resolves #23) (#24)
1 parent 1a089f0 commit 87829c5

File tree

1 file changed

+37
-3
lines changed

1 file changed

+37
-3
lines changed

lib/src/page_list_viewport.dart

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
import 'dart:async';
12
import 'dart:collection';
23
import 'dart:developer';
34
import 'dart:math' as math;
45
import 'dart:ui';
56

67
import 'package:flutter/gestures.dart';
7-
import 'package:flutter/material.dart';
88
import 'package:flutter/rendering.dart';
99
import 'package:flutter/scheduler.dart';
10+
import 'package:flutter/widgets.dart';
1011
import 'package:vector_math/vector_math_64.dart';
1112

1213
import 'logging.dart';
@@ -115,6 +116,7 @@ class PageListViewportController with ChangeNotifier {
115116
_initialPageIndex = pageIndex,
116117
_origin = Offset.zero,
117118
_previousOrigin = Offset.zero,
119+
_velocityStopwatch = Stopwatch(),
118120
_scale = scale,
119121
_previousScale = scale,
120122
_scaleVelocity = 0.0,
@@ -132,6 +134,7 @@ class PageListViewportController with ChangeNotifier {
132134
double maximumScale = double.infinity,
133135
}) : _origin = origin,
134136
_previousOrigin = origin,
137+
_velocityStopwatch = Stopwatch(),
135138
_scale = scale,
136139
_previousScale = scale,
137140
_scaleVelocity = 0.0,
@@ -145,12 +148,15 @@ class PageListViewportController with ChangeNotifier {
145148
_animationController = AnimationController(vsync: vsync) //
146149
..addListener(_onOrientationAnimationChange);
147150

151+
_velocityStopwatch.start();
148152
_scaleVelocityStopwatch.start();
149153
}
150154

151155
@override
152156
void dispose() {
153157
_animationController.dispose();
158+
_velocityStopwatch.stop();
159+
_velocityResetTimer?.cancel();
154160
_scaleVelocityStopwatch.stop();
155161
super.dispose();
156162
}
@@ -188,9 +194,11 @@ class PageListViewportController with ChangeNotifier {
188194
notifyListeners();
189195
}
190196

197+
/// The velocity of the translation of the viewport origin.
191198
Offset get velocity => _velocity;
192-
193199
Offset _velocity = Offset.zero;
200+
final Stopwatch _velocityStopwatch;
201+
Timer? _velocityResetTimer; // resets the velocity to zero if we haven't received a translation recently
194202

195203
/// The scale of the content in the viewport.
196204
double get scale => _scale;
@@ -279,6 +287,8 @@ class PageListViewportController with ChangeNotifier {
279287
_animationController.stop();
280288

281289
_origin = _getPageOffset(pageIndex, zoomLevel);
290+
_velocity = Offset.zero;
291+
_velocityStopwatch.reset();
282292

283293
notifyListeners();
284294
}
@@ -313,7 +323,10 @@ class PageListViewportController with ChangeNotifier {
313323
final desiredPageTopLeftInViewport = (viewportSize!).center(-pageFocalPointAtZoomLevel);
314324
final contentAboveDesiredPage = pageSizeAtZoomLevel.height * pageIndex;
315325
final desiredOrigin = Offset(0, -contentAboveDesiredPage) + desiredPageTopLeftInViewport;
326+
316327
_origin = _constrainOriginToViewportBounds(desiredOrigin);
328+
_velocity = Offset.zero;
329+
_velocityStopwatch.reset();
317330

318331
notifyListeners();
319332
}
@@ -426,7 +439,28 @@ class PageListViewportController with ChangeNotifier {
426439
"Origin before adjustment: $_origin. Content height: ${_viewport!.calculateContentHeight(scale)}, Scale: $scale");
427440
PageListViewportLogs.pagesListController
428441
.fine("Viewport size: ${_viewport!.size}, scaled page width: ${_viewport!.calculatePageWidth(scale)}");
429-
_origin = _constrainOriginToViewportBounds(desiredOrigin);
442+
443+
final newOrigin = _constrainOriginToViewportBounds(desiredOrigin);
444+
445+
_previousOrigin = _origin;
446+
_origin = newOrigin;
447+
448+
// Update velocity tracking.
449+
if (_velocityStopwatch.elapsedMilliseconds > 0) {
450+
_velocity = (newOrigin - _previousOrigin) / (_velocityStopwatch.elapsedMilliseconds / 1000);
451+
_velocityStopwatch.reset();
452+
_velocityResetTimer?.cancel();
453+
454+
if (_velocity.distance > 0) {
455+
// When the user is panning, we won't know when the final translation comes in.
456+
// Therefore, to eventually report a velocity of zero, we need to assume that the
457+
// absence of a message across a couple of frames indicates that we're done moving.
458+
_velocityResetTimer = Timer(const Duration(milliseconds: 32), () {
459+
_velocity = Offset.zero;
460+
notifyListeners();
461+
});
462+
}
463+
}
430464

431465
notifyListeners();
432466
}

0 commit comments

Comments
 (0)