I am trying to make a Widget that acts like the Google Calendar Week View, a ListView that can be pinch-zoomed as soon as a second pointer enters. Therefore, I created a RawGestureDetector that is supposed to declare Victory in the Arena as soon as two or more pointers are on the screen, however, when putting down one pointer and then adding a second one, without removing the first one, the GestureDetector is not even added to the arena.
I don't know if my approach is the correct one, so I would be happy to see a suggestion why I am having this issue or how to do it differently.
Steps to Reproduce
- Execute
flutter run on the code sample
- Click with one pointer and then after that, click with a second pointer leaving the first on the screen
- In the console you will see that the GestureArena doesnt even consider my second RawGestureDetector.
Expected results:
My RawGestureDetector declaring victory in the second arena
Actual results:
My RawGestureDetector not even added to the Arena:
I/flutter (13717): Gesture arena 8 ❙ ★ Opening new gesture arena.
I/flutter (13717): Gesture arena 8 ❙ Adding: PinchToZoomGestureRecognizer#f9b77
I/flutter (13717): Gesture arena 8 ❙ Adding: VerticalDragGestureRecognizer#07525(start behavior: start)
I/flutter (13717): Gesture arena 8 ❙ Closing with 2 members.
I/flutter (13717): Gesture arena 8 ❙ Accepting: VerticalDragGestureRecognizer#07525(start behavior: start)
I/flutter (13717): Gesture arena 8 ❙ Self-declared winner: VerticalDragGestureRecognizer#07525(start behavior: start)
D/EGL_emulation(13717): app_time_stats: avg=781.66ms min=5.34ms max=12373.45ms count=16
I/flutter (13717): Gesture arena 9 ❙ ★ Opening new gesture arena.
I/flutter (13717): Gesture arena 9 ❙ Adding: VerticalDragGestureRecognizer#07525(start behavior: start)
I/flutter (13717): Gesture arena 9 ❙ Accepting: VerticalDragGestureRecognizer#07525(start behavior: start)
I/flutter (13717): Gesture arena 9 ❙ Closing with 1 member.
I/flutter (13717): Gesture arena 9 ❙ Default winner: VerticalDragGestureRecognizer#07525(start behavior: start)
Code sample
Widget for Tests:
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
void main() {
debugPrintGestureArenaDiagnostics = true;
runApp(const MaterialApp(home: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: RawGestureDetector(
gestures: <Type, GestureRecognizerFactory>{
PinchToZoomGestureRecognizer: GestureRecognizerFactoryWithHandlers<
PinchToZoomGestureRecognizer>(
() => PinchToZoomGestureRecognizer(
onScaleStart: () {},
onScaleUpdate: () {},
onScaleEnd: () {},
),
(instance) {},
),
},
child: Container(
width: MediaQuery.of(context).size.width,
decoration: const BoxDecoration(
color: Colors.blueGrey,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(
100,
(index) => Text("Item $index"),
),
),
),
),
),
);
}
}
GestureRecognizer:
class PinchToZoomGestureRecognizer extends OneSequenceGestureRecognizer {
final void Function() onScaleStart;
final void Function() onScaleUpdate;
final void Function() onScaleEnd;
PinchToZoomGestureRecognizer({
required this.onScaleStart,
required this.onScaleUpdate,
required this.onScaleEnd,
});
@override
String get debugDescription => '$runtimeType';
Map<int, Offset> pointerPositionMap = {};
@override
void addAllowedPointer(PointerEvent event) {
startTrackingPointer(event.pointer);
pointerPositionMap[event.pointer] = event.position;
if (pointerPositionMap.length >= 2) {
resolve(GestureDisposition.accepted);
}
}
@override
void handleEvent(PointerEvent event) {
if (event is PointerMoveEvent) {
pointerPositionMap[event.pointer] = event.position;
return;
} else if (event is PointerDownEvent) {
pointerPositionMap[event.pointer] = event.position;
} else if (event is PointerUpEvent || event is PointerCancelEvent) {
stopTrackingPointer(event.pointer);
pointerPositionMap.remove(event.pointer);
}
if (pointerPositionMap.length >= 2) {
resolve(GestureDisposition.accepted);
}
}
@override
void didStopTrackingLastPointer(int pointer) {
resolve(GestureDisposition.rejected);
}
}
flutter doctor -v
[✓] Flutter (Channel stable, 3.0.5, on Microsoft Windows [Version 10.0.19044.2006], locale de-DE)
• Flutter version 3.0.5 at C:\Users\Laslo\flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision f1875d570e (3 months ago), 2022-07-13 11:24:16 -0700
• Engine revision e85ea0e79c
• Dart version 2.17.6
• DevTools version 2.12.2
[!] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
• Android SDK at C:\Users\Laslo\AppData\Local\Android\sdk
✗ cmdline-tools component is missing
Run `path/to/sdkmanager --install "cmdline-tools;latest"`
See https://developer.android.com/studio/command-line for more details.
✗ Android license status unknown.
Run `flutter doctor --android-licenses` to accept the SDK licenses.
See https://flutter.dev/docs/get-started/install/windows#android-setup for more details.
[✓] Chrome - develop for the web
• Chrome at C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
[✗] Visual Studio - develop for Windows
✗ Visual Studio not installed; this is necessary for Windows development.
Download at https://visualstudio.microsoft.com/downloads/.
Please install the "Desktop development with C++" workload, including all of its default components
[!] Android Studio (not installed)
• Android Studio not found; download from https://developer.android.com/studio/index.html
(or visit https://flutter.dev/docs/get-started/install/windows#android-setup for detailed instructions).
[✓] IntelliJ IDEA Ultimate Edition (version 2022.2)
• IntelliJ at C:\Users\Laslo\AppData\Local\JetBrains\Toolbox\apps\IDEA-U\ch-0\222.4345.14
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin version 222.4167.21
[✓] VS Code (version 1.71.2)
• VS Code at C:\Users\Laslo\AppData\Local\Programs\Microsoft VS Code
• Flutter extension can be installed from:
🔨 https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter
[✓] Connected device (3 available)
• Windows (desktop) • windows • windows-x64 • Microsoft Windows [Version 10.0.19044.2006]
• Chrome (web) • chrome • web-javascript • Google Chrome 105.0.5195.127
• Edge (web) • edge • web-javascript • Microsoft Edge 105.0.1343.33
[✓] HTTP Host Availability
• All required HTTP hosts are available
! Doctor found issues in 3 categories.
I am trying to make a Widget that acts like the Google Calendar Week View, a ListView that can be pinch-zoomed as soon as a second pointer enters. Therefore, I created a RawGestureDetector that is supposed to declare Victory in the Arena as soon as two or more pointers are on the screen, however, when putting down one pointer and then adding a second one, without removing the first one, the GestureDetector is not even added to the arena.
I don't know if my approach is the correct one, so I would be happy to see a suggestion why I am having this issue or how to do it differently.
Steps to Reproduce
flutter runon the code sampleExpected results:
My RawGestureDetector declaring victory in the second arena
Actual results:
My RawGestureDetector not even added to the Arena:
Code sample
Widget for Tests:
GestureRecognizer:
flutter doctor -v