1
+ import 'dart:async' ;
1
2
import 'dart:collection' ;
2
3
import 'dart:developer' ;
3
4
import 'dart:math' as math;
4
5
import 'dart:ui' ;
5
6
6
7
import 'package:flutter/gestures.dart' ;
7
- import 'package:flutter/material.dart' ;
8
8
import 'package:flutter/rendering.dart' ;
9
9
import 'package:flutter/scheduler.dart' ;
10
+ import 'package:flutter/widgets.dart' ;
10
11
import 'package:vector_math/vector_math_64.dart' ;
11
12
12
13
import 'logging.dart' ;
@@ -115,6 +116,7 @@ class PageListViewportController with ChangeNotifier {
115
116
_initialPageIndex = pageIndex,
116
117
_origin = Offset .zero,
117
118
_previousOrigin = Offset .zero,
119
+ _velocityStopwatch = Stopwatch (),
118
120
_scale = scale,
119
121
_previousScale = scale,
120
122
_scaleVelocity = 0.0 ,
@@ -132,6 +134,7 @@ class PageListViewportController with ChangeNotifier {
132
134
double maximumScale = double .infinity,
133
135
}) : _origin = origin,
134
136
_previousOrigin = origin,
137
+ _velocityStopwatch = Stopwatch (),
135
138
_scale = scale,
136
139
_previousScale = scale,
137
140
_scaleVelocity = 0.0 ,
@@ -145,12 +148,15 @@ class PageListViewportController with ChangeNotifier {
145
148
_animationController = AnimationController (vsync: vsync) //
146
149
..addListener (_onOrientationAnimationChange);
147
150
151
+ _velocityStopwatch.start ();
148
152
_scaleVelocityStopwatch.start ();
149
153
}
150
154
151
155
@override
152
156
void dispose () {
153
157
_animationController.dispose ();
158
+ _velocityStopwatch.stop ();
159
+ _velocityResetTimer? .cancel ();
154
160
_scaleVelocityStopwatch.stop ();
155
161
super .dispose ();
156
162
}
@@ -188,9 +194,11 @@ class PageListViewportController with ChangeNotifier {
188
194
notifyListeners ();
189
195
}
190
196
197
+ /// The velocity of the translation of the viewport origin.
191
198
Offset get velocity => _velocity;
192
-
193
199
Offset _velocity = Offset .zero;
200
+ final Stopwatch _velocityStopwatch;
201
+ Timer ? _velocityResetTimer; // resets the velocity to zero if we haven't received a translation recently
194
202
195
203
/// The scale of the content in the viewport.
196
204
double get scale => _scale;
@@ -279,6 +287,8 @@ class PageListViewportController with ChangeNotifier {
279
287
_animationController.stop ();
280
288
281
289
_origin = _getPageOffset (pageIndex, zoomLevel);
290
+ _velocity = Offset .zero;
291
+ _velocityStopwatch.reset ();
282
292
283
293
notifyListeners ();
284
294
}
@@ -313,7 +323,10 @@ class PageListViewportController with ChangeNotifier {
313
323
final desiredPageTopLeftInViewport = (viewportSize! ).center (- pageFocalPointAtZoomLevel);
314
324
final contentAboveDesiredPage = pageSizeAtZoomLevel.height * pageIndex;
315
325
final desiredOrigin = Offset (0 , - contentAboveDesiredPage) + desiredPageTopLeftInViewport;
326
+
316
327
_origin = _constrainOriginToViewportBounds (desiredOrigin);
328
+ _velocity = Offset .zero;
329
+ _velocityStopwatch.reset ();
317
330
318
331
notifyListeners ();
319
332
}
@@ -426,7 +439,28 @@ class PageListViewportController with ChangeNotifier {
426
439
"Origin before adjustment: $_origin . Content height: ${_viewport !.calculateContentHeight (scale )}, Scale: $scale " );
427
440
PageListViewportLogs .pagesListController
428
441
.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
+ }
430
464
431
465
notifyListeners ();
432
466
}
0 commit comments