Skip to content

Commit f09976a

Browse files
committed
scroll [nfc]: Introduce SimulationDrivenScrollActivity
In order to implement the "scroll to bottom" button in a way that behaves well when scrolling to the growth end of a sliver -- in particular, when scrolling to the end of the message list after we split it into back-to-back slivers -- we'll want some differences from the behavior provided by DrivenScrollActivity, which we've used up until now (originally via the `animateTo` method). That calls for our own ScrollActivity subclass, ScrollToEndActivity. We'll want most of the same behavior as DrivenScrollActivity, with just a couple of changes; but one of the places we want to change isn't among the places that DrivenScrollActivity exposes for subclassing. So add this class, based on DrivenScrollActivity but with a customization point added in the additional spot we'll need. Originally there were two additional customization points needed. After first drafting this change, I sent those upstream as two PRs: flutter/flutter#166730 flutter/flutter#166731 The first one has already landed in DrivenScrollActivity: the applyMoveTo method now overridden by ScrollToEndActivity in a previous commit. The other one, a `.simulation` constructor, is pending. A "TODO(upstream)" comment points to that PR, because once it also merges we can dispense with this class.
1 parent 5233d6d commit f09976a

File tree

1 file changed

+72
-0
lines changed

1 file changed

+72
-0
lines changed

lib/widgets/scrolling.dart

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,78 @@ class RenderCustomPaintOrderViewport extends RenderViewport {
249249
}
250250
}
251251

252+
/// Like [DrivenScrollActivity], but accepting a general [Simulation].
253+
// TODO(upstream): https://github.com/flutter/flutter/pull/166731
254+
class SimulationDrivenScrollActivity extends ScrollActivity {
255+
SimulationDrivenScrollActivity.simulation(
256+
super.delegate,
257+
Simulation simulation, {
258+
required TickerProvider vsync,
259+
}) {
260+
_controller = AnimationController.unbounded(vsync: vsync)
261+
..addListener(_tick)
262+
..animateWith(simulation).whenComplete(_end);
263+
}
264+
265+
late final AnimationController _controller;
266+
bool _isDisposed = false;
267+
268+
void _tick() {
269+
if (!applyMoveTo(_controller.value)) {
270+
delegate.goIdle();
271+
}
272+
}
273+
274+
/// Move the position to the given location.
275+
///
276+
/// Returns true if the position was fully applied,
277+
/// false if there was overflow.
278+
bool applyMoveTo(double value) {
279+
return delegate.setPixels(value).abs() < precisionErrorTolerance;
280+
}
281+
282+
void _end() {
283+
if (!_isDisposed) {
284+
delegate.goBallistic(velocity);
285+
}
286+
}
287+
288+
@override
289+
void dispatchOverscrollNotification(
290+
ScrollMetrics metrics,
291+
BuildContext context,
292+
double overscroll,
293+
) {
294+
OverscrollNotification(
295+
metrics: metrics,
296+
context: context,
297+
overscroll: overscroll,
298+
velocity: velocity,
299+
).dispatch(context);
300+
}
301+
302+
@override
303+
bool get shouldIgnorePointer => true;
304+
305+
@override
306+
bool get isScrolling => true;
307+
308+
@override
309+
double get velocity => _controller.velocity;
310+
311+
@override
312+
void dispose() {
313+
_controller.dispose();
314+
_isDisposed = true;
315+
super.dispose();
316+
}
317+
318+
@override
319+
String toString() {
320+
return '${describeIdentity(this)}($_controller)';
321+
}
322+
}
323+
252324
/// An activity that animates a scroll view smoothly to its end.
253325
///
254326
/// In particular this drives the "scroll to bottom" button

0 commit comments

Comments
 (0)