mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Scroll inertia cancel [framework] (#106891)
This commit is contained in:
parent
bf22b7ae73
commit
22f51c34c6
@ -259,9 +259,15 @@ class PointerEventConverter {
|
||||
scrollDelta: scrollDelta,
|
||||
embedderId: datum.embedderId,
|
||||
);
|
||||
case ui.PointerSignalKind.scrollInertiaCancel:
|
||||
return PointerScrollInertiaCancelEvent(
|
||||
timeStamp: timeStamp,
|
||||
kind: kind,
|
||||
device: datum.device,
|
||||
position: position,
|
||||
embedderId: datum.embedderId,
|
||||
);
|
||||
case ui.PointerSignalKind.unknown:
|
||||
default: // ignore: no_default_cases, to allow adding a new [PointerSignalKind]
|
||||
// TODO(moffatman): Remove after landing https://github.com/flutter/engine/pull/34402
|
||||
// This branch should already have 'unknown' filtered out, but
|
||||
// we don't want to return anything or miss if someone adds a new
|
||||
// enumeration to PointerSignalKind.
|
||||
|
@ -1830,6 +1830,91 @@ class _TransformedPointerScrollEvent extends _TransformedPointerEvent with _Copy
|
||||
}
|
||||
}
|
||||
|
||||
mixin _CopyPointerScrollInertiaCancelEvent on PointerEvent {
|
||||
@override
|
||||
PointerScrollInertiaCancelEvent copyWith({
|
||||
Duration? timeStamp,
|
||||
int? pointer,
|
||||
PointerDeviceKind? kind,
|
||||
int? device,
|
||||
Offset? position,
|
||||
Offset? delta,
|
||||
int? buttons,
|
||||
bool? obscured,
|
||||
double? pressure,
|
||||
double? pressureMin,
|
||||
double? pressureMax,
|
||||
double? distance,
|
||||
double? distanceMax,
|
||||
double? size,
|
||||
double? radiusMajor,
|
||||
double? radiusMinor,
|
||||
double? radiusMin,
|
||||
double? radiusMax,
|
||||
double? orientation,
|
||||
double? tilt,
|
||||
bool? synthesized,
|
||||
int? embedderId,
|
||||
}) {
|
||||
return PointerScrollInertiaCancelEvent(
|
||||
timeStamp: timeStamp ?? this.timeStamp,
|
||||
kind: kind ?? this.kind,
|
||||
device: device ?? this.device,
|
||||
position: position ?? this.position,
|
||||
embedderId: embedderId ?? this.embedderId,
|
||||
).transformed(transform);
|
||||
}
|
||||
}
|
||||
|
||||
/// The pointer issued a scroll-inertia cancel event.
|
||||
///
|
||||
/// Touching the trackpad immediately after a scroll is an example of an event
|
||||
/// that would create a [PointerScrollInertiaCancelEvent].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Listener.onPointerSignal], which allows callers to be notified of these
|
||||
/// events in a widget tree.
|
||||
/// * [PointerSignalResolver], which provides an opt-in mechanism whereby
|
||||
/// participating agents may disambiguate an event's target.
|
||||
class PointerScrollInertiaCancelEvent extends PointerSignalEvent with _PointerEventDescription, _CopyPointerScrollInertiaCancelEvent {
|
||||
/// Creates a pointer scroll-inertia cancel event.
|
||||
///
|
||||
/// All of the arguments must be non-null.
|
||||
const PointerScrollInertiaCancelEvent({
|
||||
super.timeStamp,
|
||||
super.kind,
|
||||
super.device,
|
||||
super.position,
|
||||
super.embedderId,
|
||||
}) : assert(timeStamp != null),
|
||||
assert(kind != null),
|
||||
assert(device != null),
|
||||
assert(position != null);
|
||||
|
||||
@override
|
||||
PointerScrollInertiaCancelEvent transformed(Matrix4? transform) {
|
||||
if (transform == null || transform == this.transform) {
|
||||
return this;
|
||||
}
|
||||
return _TransformedPointerScrollInertiaCancelEvent(original as PointerScrollInertiaCancelEvent? ?? this, transform);
|
||||
}
|
||||
}
|
||||
|
||||
class _TransformedPointerScrollInertiaCancelEvent extends _TransformedPointerEvent with _CopyPointerScrollInertiaCancelEvent implements PointerScrollInertiaCancelEvent {
|
||||
_TransformedPointerScrollInertiaCancelEvent(this.original, this.transform)
|
||||
: assert(original != null), assert(transform != null);
|
||||
|
||||
@override
|
||||
final PointerScrollInertiaCancelEvent original;
|
||||
|
||||
@override
|
||||
final Matrix4 transform;
|
||||
|
||||
@override
|
||||
PointerScrollInertiaCancelEvent transformed(Matrix4? transform) => original.transformed(transform);
|
||||
}
|
||||
|
||||
mixin _CopyPointerPanZoomStartEvent on PointerEvent {
|
||||
@override
|
||||
PointerPanZoomStartEvent copyWith({
|
||||
|
@ -731,6 +731,9 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
|
||||
if (delta != 0.0 && targetScrollOffset != position.pixels) {
|
||||
GestureBinding.instance.pointerSignalResolver.register(event, _handlePointerScroll);
|
||||
}
|
||||
} else if (event is PointerScrollInertiaCancelEvent) {
|
||||
position.jumpTo(position.pixels);
|
||||
// Don't use the pointer signal resolver, all hit-tested scrollables should stop.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1427,6 +1427,22 @@ void main() {
|
||||
expect(syntheticScrollableNode!.hasFlag(ui.SemanticsFlag.hasImplicitScrolling), isTrue);
|
||||
handle.dispose();
|
||||
});
|
||||
|
||||
testWidgets('Scroll inertia cancel event', (WidgetTester tester) async {
|
||||
await pumpTest(tester, null);
|
||||
await tester.fling(find.byType(Scrollable), const Offset(0.0, -dragOffset), 1000.0);
|
||||
expect(getScrollOffset(tester), dragOffset);
|
||||
await tester.pump(); // trigger fling
|
||||
expect(getScrollOffset(tester), dragOffset);
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
final TestPointer testPointer = TestPointer(1, ui.PointerDeviceKind.mouse);
|
||||
await tester.sendEventToBinding(testPointer.hover(tester.getCenter(find.byType(Scrollable))));
|
||||
await tester.sendEventToBinding(testPointer.scrollInertiaCancel()); // Cancel partway through.
|
||||
await tester.pump();
|
||||
expect(getScrollOffset(tester), closeTo(333.2944, 0.0001));
|
||||
await tester.pump(const Duration(milliseconds: 4800));
|
||||
expect(getScrollOffset(tester), closeTo(333.2944, 0.0001));
|
||||
});
|
||||
}
|
||||
|
||||
// ignore: must_be_immutable
|
||||
|
@ -304,6 +304,23 @@ class TestPointer {
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a [PointerScrollInertiaCancelEvent] (e.g., user resting their finger on the trackpad).
|
||||
///
|
||||
/// By default, the time stamp on the event is [Duration.zero]. You can give a
|
||||
/// specific time stamp by passing the `timeStamp` argument.
|
||||
PointerScrollInertiaCancelEvent scrollInertiaCancel({
|
||||
Duration timeStamp = Duration.zero,
|
||||
}) {
|
||||
assert(kind != PointerDeviceKind.touch, "Touch pointers can't generate pointer signal events");
|
||||
assert(location != null);
|
||||
return PointerScrollInertiaCancelEvent(
|
||||
timeStamp: timeStamp,
|
||||
kind: kind,
|
||||
device: _device,
|
||||
position: location!
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a [PointerPanZoomStartEvent] (e.g., trackpad scroll; not scroll wheel
|
||||
/// or finger-drag scroll) with the given delta.
|
||||
///
|
||||
|
Loading…
Reference in New Issue
Block a user