Skip to content

Commit 778b3fa

Browse files
authored
support updating dragDecices at runtime (#120336)
1 parent ed35c80 commit 778b3fa

File tree

5 files changed

+130
-17
lines changed

5 files changed

+130
-17
lines changed

packages/flutter/lib/src/gestures/recognizer.dart

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,9 @@ abstract class GestureRecognizer extends GestureArenaMember with DiagnosticableT
7878
/// {@endtemplate}
7979
GestureRecognizer({
8080
this.debugOwner,
81-
Set<PointerDeviceKind>? supportedDevices,
81+
this.supportedDevices,
8282
AllowedButtonsFilter? allowedButtonsFilter,
83-
}) : _supportedDevices = supportedDevices,
84-
_allowedButtonsFilter = allowedButtonsFilter ?? _defaultButtonAcceptBehavior;
83+
}) : _allowedButtonsFilter = allowedButtonsFilter ?? _defaultButtonAcceptBehavior;
8584

8685
/// The recognizer's owner.
8786
///
@@ -97,7 +96,7 @@ abstract class GestureRecognizer extends GestureArenaMember with DiagnosticableT
9796
/// `supportedDevices` in the constructor, or the currently deprecated `kind`.
9897
/// These cannot both be set. If both are null, events from all device kinds will be
9998
/// tracked and recognized.
100-
final Set<PointerDeviceKind>? _supportedDevices;
99+
Set<PointerDeviceKind>? supportedDevices;
101100

102101
/// {@template flutter.gestures.multidrag._allowedButtonsFilter}
103102
/// Called when interaction starts. This limits the dragging behavior
@@ -209,8 +208,8 @@ abstract class GestureRecognizer extends GestureArenaMember with DiagnosticableT
209208
/// Checks whether or not a pointer is allowed to be tracked by this recognizer.
210209
@protected
211210
bool isPointerAllowed(PointerDownEvent event) {
212-
return (_supportedDevices == null ||
213-
_supportedDevices!.contains(event.kind)) &&
211+
return (supportedDevices == null ||
212+
supportedDevices!.contains(event.kind)) &&
214213
_allowedButtonsFilter(event.buttons);
215214
}
216215

@@ -223,7 +222,7 @@ abstract class GestureRecognizer extends GestureArenaMember with DiagnosticableT
223222
/// Checks whether or not a pointer pan/zoom is allowed to be tracked by this recognizer.
224223
@protected
225224
bool isPointerPanZoomAllowed(PointerPanZoomStartEvent event) {
226-
return _supportedDevices == null || _supportedDevices!.contains(event.kind);
225+
return supportedDevices == null || supportedDevices!.contains(event.kind);
227226
}
228227

229228
/// For a given pointer ID, returns the device kind associated with it.

packages/flutter/lib/src/widgets/gesture_detector.dart

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,7 +1050,8 @@ class GestureDetector extends StatelessWidget {
10501050
..onTertiaryTapDown = onTertiaryTapDown
10511051
..onTertiaryTapUp = onTertiaryTapUp
10521052
..onTertiaryTapCancel = onTertiaryTapCancel
1053-
..gestureSettings = gestureSettings;
1053+
..gestureSettings = gestureSettings
1054+
..supportedDevices = supportedDevices;
10541055
},
10551056
);
10561057
}
@@ -1065,7 +1066,8 @@ class GestureDetector extends StatelessWidget {
10651066
..onDoubleTapDown = onDoubleTapDown
10661067
..onDoubleTap = onDoubleTap
10671068
..onDoubleTapCancel = onDoubleTapCancel
1068-
..gestureSettings = gestureSettings;
1069+
..gestureSettings = gestureSettings
1070+
..supportedDevices = supportedDevices;
10691071
},
10701072
);
10711073
}
@@ -1116,7 +1118,8 @@ class GestureDetector extends StatelessWidget {
11161118
..onTertiaryLongPressMoveUpdate = onTertiaryLongPressMoveUpdate
11171119
..onTertiaryLongPressUp = onTertiaryLongPressUp
11181120
..onTertiaryLongPressEnd = onTertiaryLongPressEnd
1119-
..gestureSettings = gestureSettings;
1121+
..gestureSettings = gestureSettings
1122+
..supportedDevices = supportedDevices;
11201123
},
11211124
);
11221125
}
@@ -1136,7 +1139,8 @@ class GestureDetector extends StatelessWidget {
11361139
..onEnd = onVerticalDragEnd
11371140
..onCancel = onVerticalDragCancel
11381141
..dragStartBehavior = dragStartBehavior
1139-
..gestureSettings = gestureSettings;
1142+
..gestureSettings = gestureSettings
1143+
..supportedDevices = supportedDevices;
11401144
},
11411145
);
11421146
}
@@ -1156,7 +1160,8 @@ class GestureDetector extends StatelessWidget {
11561160
..onEnd = onHorizontalDragEnd
11571161
..onCancel = onHorizontalDragCancel
11581162
..dragStartBehavior = dragStartBehavior
1159-
..gestureSettings = gestureSettings;
1163+
..gestureSettings = gestureSettings
1164+
..supportedDevices = supportedDevices;
11601165
},
11611166
);
11621167
}
@@ -1176,7 +1181,8 @@ class GestureDetector extends StatelessWidget {
11761181
..onEnd = onPanEnd
11771182
..onCancel = onPanCancel
11781183
..dragStartBehavior = dragStartBehavior
1179-
..gestureSettings = gestureSettings;
1184+
..gestureSettings = gestureSettings
1185+
..supportedDevices = supportedDevices;
11801186
},
11811187
);
11821188
}
@@ -1192,7 +1198,8 @@ class GestureDetector extends StatelessWidget {
11921198
..dragStartBehavior = dragStartBehavior
11931199
..gestureSettings = gestureSettings
11941200
..trackpadScrollCausesScale = trackpadScrollCausesScale
1195-
..trackpadScrollToScaleFactor = trackpadScrollToScaleFactor;
1201+
..trackpadScrollToScaleFactor = trackpadScrollToScaleFactor
1202+
..supportedDevices = supportedDevices;
11961203
},
11971204
);
11981205
}
@@ -1209,7 +1216,8 @@ class GestureDetector extends StatelessWidget {
12091216
..onPeak = onForcePressPeak
12101217
..onUpdate = onForcePressUpdate
12111218
..onEnd = onForcePressEnd
1212-
..gestureSettings = gestureSettings;
1219+
..gestureSettings = gestureSettings
1220+
..supportedDevices = supportedDevices;
12131221
},
12141222
);
12151223
}

packages/flutter/lib/src/widgets/scrollable.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,8 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
630630
..maxFlingVelocity = _physics?.maxFlingVelocity
631631
..velocityTrackerBuilder = _configuration.velocityTrackerBuilder(context)
632632
..dragStartBehavior = widget.dragStartBehavior
633-
..gestureSettings = _mediaQueryGestureSettings;
633+
..gestureSettings = _mediaQueryGestureSettings
634+
..supportedDevices = _configuration.dragDevices;
634635
},
635636
),
636637
};
@@ -651,7 +652,8 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
651652
..maxFlingVelocity = _physics?.maxFlingVelocity
652653
..velocityTrackerBuilder = _configuration.velocityTrackerBuilder(context)
653654
..dragStartBehavior = widget.dragStartBehavior
654-
..gestureSettings = _mediaQueryGestureSettings;
655+
..gestureSettings = _mediaQueryGestureSettings
656+
..supportedDevices = _configuration.dragDevices;
655657
},
656658
),
657659
};

packages/flutter/test/widgets/gesture_detector_test.dart

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,76 @@ void main() {
876876
});
877877
});
878878

879+
testWidgets('supportedDevices update test', (WidgetTester tester) async {
880+
// Regression test for https://github.com/flutter/flutter/issues/111716
881+
bool didStartPan = false;
882+
Offset? panDelta;
883+
bool didEndPan = false;
884+
Widget buildFrame(Set<PointerDeviceKind>? supportedDevices) {
885+
return GestureDetector(
886+
onPanStart: (DragStartDetails details) {
887+
didStartPan = true;
888+
},
889+
onPanUpdate: (DragUpdateDetails details) {
890+
panDelta = (panDelta ?? Offset.zero) + details.delta;
891+
},
892+
onPanEnd: (DragEndDetails details) {
893+
didEndPan = true;
894+
},
895+
supportedDevices: supportedDevices,
896+
child: Container(
897+
color: const Color(0xFF00FF00),
898+
)
899+
);
900+
}
901+
902+
await tester.pumpWidget(buildFrame(<PointerDeviceKind>{PointerDeviceKind.mouse}));
903+
904+
expect(didStartPan, isFalse);
905+
expect(panDelta, isNull);
906+
expect(didEndPan, isFalse);
907+
908+
await tester.dragFrom(const Offset(10.0, 10.0), const Offset(20.0, 30.0), kind: PointerDeviceKind.mouse);
909+
910+
// Matching device should allow gesture.
911+
expect(didStartPan, isTrue);
912+
expect(panDelta!.dx, 20.0);
913+
expect(panDelta!.dy, 30.0);
914+
expect(didEndPan, isTrue);
915+
916+
didStartPan = false;
917+
panDelta = null;
918+
didEndPan = false;
919+
920+
await tester.pumpWidget(buildFrame(<PointerDeviceKind>{PointerDeviceKind.stylus}));
921+
922+
await tester.dragFrom(const Offset(10.0, 10.0), const Offset(20.0, 30.0), kind: PointerDeviceKind.mouse);
923+
// Non-matching device should not lead to any callbacks.
924+
expect(didStartPan, isFalse);
925+
expect(panDelta, isNull);
926+
expect(didEndPan, isFalse);
927+
928+
await tester.dragFrom(const Offset(10.0, 10.0), const Offset(20.0, 30.0), kind: PointerDeviceKind.stylus);
929+
// Matching device should allow gesture.
930+
expect(didStartPan, isTrue);
931+
expect(panDelta!.dx, 20.0);
932+
expect(panDelta!.dy, 30.0);
933+
expect(didEndPan, isTrue);
934+
935+
didStartPan = false;
936+
panDelta = null;
937+
didEndPan = false;
938+
939+
// If set to null, events from all device types will be recognized
940+
await tester.pumpWidget(buildFrame(null));
941+
942+
await tester.dragFrom(const Offset(10.0, 10.0), const Offset(20.0, 30.0), kind: PointerDeviceKind.unknown);
943+
expect(didStartPan, isTrue);
944+
expect(panDelta!.dx, 20.0);
945+
expect(panDelta!.dy, 30.0);
946+
expect(didEndPan, isTrue);
947+
});
948+
879949
testWidgets('supportedDevices is respected', (WidgetTester tester) async {
880950
bool didStartPan = false;
881951
Offset? panDelta;

packages/flutter/test/widgets/scrollable_test.dart

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,6 +1471,40 @@ void main() {
14711471
await tester.pump();
14721472
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS, TargetPlatform.android }));
14731473

1474+
testWidgets("Support updating 'ScrollBehavior.dragDevices' at runtime", (WidgetTester tester) async {
1475+
// Regression test for https://github.com/flutter/flutter/issues/111716
1476+
Widget buildFrame(Set<ui.PointerDeviceKind>? dragDevices) {
1477+
return MaterialApp(
1478+
scrollBehavior: const NoScrollbarBehavior().copyWith(
1479+
dragDevices: dragDevices,
1480+
),
1481+
home: ListView.builder(
1482+
itemCount: 1000,
1483+
itemBuilder: (BuildContext context, int index) {
1484+
return Text('Item $index');
1485+
},
1486+
),
1487+
);
1488+
}
1489+
1490+
await tester.pumpWidget(buildFrame(<ui.PointerDeviceKind>{ui.PointerDeviceKind.mouse}));
1491+
await tester.drag(find.byType(Scrollable), const Offset(0.0, -100.0), kind: ui.PointerDeviceKind.mouse);
1492+
1493+
// Matching device should allow user scrolling.
1494+
expect(getScrollOffset(tester), 100.0);
1495+
1496+
await tester.pumpWidget(buildFrame(<ui.PointerDeviceKind>{ui.PointerDeviceKind.stylus}));
1497+
await tester.drag(find.byType(Scrollable), const Offset(0.0, -100.0), kind: ui.PointerDeviceKind.mouse);
1498+
1499+
// Non-matching device should not allow user scrolling.
1500+
expect(getScrollOffset(tester), 100.0);
1501+
1502+
await tester.drag(find.byType(Scrollable), const Offset(0.0, -100.0), kind: ui.PointerDeviceKind.stylus);
1503+
1504+
// Matching device should allow user scrolling.
1505+
expect(getScrollOffset(tester), 200.0);
1506+
});
1507+
14741508
testWidgets('Does scroll with mouse pointer drag when behavior is not configured to ignore them', (WidgetTester tester) async {
14751509
await pumpTest(tester, debugDefaultTargetPlatformOverride);
14761510
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(Scrollable), warnIfMissed: true), kind: ui.PointerDeviceKind.mouse);

0 commit comments

Comments
 (0)