@@ -3240,20 +3240,254 @@ The provided ScrollController cannot be shared by multiple ScrollView widgets.''
3240
3240
expect (scrollController.offset, 0.0 );
3241
3241
expect (scrollController.position.maxScrollExtent, 0.0 );
3242
3242
3243
- await tester.drag (find.byType (SingleChildScrollView ), const Offset (0 , - 100 ), kind: PointerDeviceKind .trackpad);
3243
+ await tester.trackpadFling (find.byType (SingleChildScrollView ), const Offset (0 , - 100 ), 500 );
3244
+ await tester.pumpAndSettle ();
3245
+ expect (scrollController.offset, 0.0 );
3246
+
3247
+ await tester.trackpadFling (find.byType (SingleChildScrollView ), const Offset (0 , 100 ), 500 );
3244
3248
await tester.pumpAndSettle ();
3245
3249
expect (scrollController.offset, 0.0 );
3246
- expect (scrollController.position.maxScrollExtent, 0.0 );
3247
3250
3248
3251
await tester.pumpWidget (buildFrame (700 ));
3249
3252
await tester.pumpAndSettle ();
3250
3253
expect (scrollController.offset, 0.0 );
3251
3254
expect (scrollController.position.maxScrollExtent, 100.0 );
3252
3255
3253
- await tester.drag (find.byType (SingleChildScrollView ), const Offset (0 , - 100 ), kind : PointerDeviceKind .trackpad );
3256
+ await tester.trackpadFling (find.byType (SingleChildScrollView ), const Offset (0 , - 100 ), 500 );
3254
3257
await tester.pumpAndSettle ();
3255
3258
expect (scrollController.offset, 100.0 );
3256
- expect (scrollController.position.maxScrollExtent, 100.0 );
3257
3259
3260
+ await tester.trackpadFling (find.byType (SingleChildScrollView ), const Offset (0 , 100 ), 500 );
3261
+ await tester.pumpAndSettle ();
3262
+ expect (scrollController.offset, 0.0 );
3263
+ });
3264
+
3265
+ testWidgets ('Desktop trackpad drag direction: -X,-Y produces positive scroll offset changes' , (WidgetTester tester) async {
3266
+ // Regression test for https://github.com/flutter/flutter/issues/149999.
3267
+ // This test doesn't strictly test the scrollbar: trackpad flings
3268
+ // that begin in the center of the scrollable are handled by the
3269
+ // scrollable, not the scrollbar. However: the scrollbar widget does
3270
+ // contain the scrollable and this test verifies that it doesn't
3271
+ // inadvertantly handle thumb down/start/update/end gestures due
3272
+ // to trackpad pan/zoom events. Those callbacks are prevented by
3273
+ // the overrides of isPointerPanZoomAllowed in the scrollbar
3274
+ // gesture recognizers.
3275
+
3276
+ final ScrollController scrollController = ScrollController ();
3277
+ addTearDown (scrollController.dispose);
3278
+
3279
+ Widget buildFrame (Axis scrollDirection) {
3280
+ return Directionality (
3281
+ textDirection: TextDirection .ltr,
3282
+ child: MediaQuery (
3283
+ data: const MediaQueryData (),
3284
+ child: RawScrollbar (
3285
+ controller: scrollController,
3286
+ child: SingleChildScrollView (
3287
+ scrollDirection: scrollDirection,
3288
+ controller: scrollController,
3289
+ child: const SizedBox (width: 1600 , height: 1200 ),
3290
+ ),
3291
+ ),
3292
+ ),
3293
+ );
3294
+ }
3295
+
3296
+ // Vertical scrolling: -Y trackpad motion produces positive scroll offset change
3297
+
3298
+ await tester.pumpWidget (buildFrame (Axis .vertical));
3299
+ expect (scrollController.offset, 0 );
3300
+ expect (scrollController.position.maxScrollExtent, 600 );
3301
+
3302
+ await tester.trackpadFling (find.byType (SingleChildScrollView ), const Offset (0 , - 600 ), 500 );
3303
+ await tester.pumpAndSettle ();
3304
+ expect (scrollController.offset, 600 );
3305
+
3306
+ await tester.trackpadFling (find.byType (SingleChildScrollView ), const Offset (0 , 600 ), 500 );
3307
+ await tester.pumpAndSettle ();
3308
+ expect (scrollController.offset, 0 );
3309
+
3310
+ // Overscroll is OK for (vertical) trackpad gestures.
3311
+
3312
+ await tester.trackpadFling (find.byType (SingleChildScrollView ), const Offset (0 , - 100 ), 500 );
3313
+ await tester.pumpAndSettle ();
3314
+ expect (scrollController.offset, greaterThan (100 ));
3315
+ scrollController.jumpTo (600 );
3316
+
3317
+ await tester.trackpadFling (find.byType (SingleChildScrollView ), const Offset (0 , 100 ), 500 );
3318
+ await tester.pumpAndSettle ();
3319
+ expect (scrollController.offset, lessThan (500 ));
3320
+ scrollController.jumpTo (0 );
3321
+
3322
+ // Horizontal scrolling: -X trackpad motion produces positive scroll offset change
3323
+
3324
+ await tester.pumpWidget (buildFrame (Axis .horizontal));
3325
+ expect (scrollController.offset, 0 );
3326
+ expect (scrollController.position.maxScrollExtent, 800 );
3327
+
3328
+ await tester.trackpadFling (find.byType (SingleChildScrollView ), const Offset (- 800 , 0 ), 500 );
3329
+ await tester.pumpAndSettle ();
3330
+ expect (scrollController.offset, 800 );
3331
+
3332
+ await tester.trackpadFling (find.byType (SingleChildScrollView ), const Offset (800 , 0 ), 500 );
3333
+ await tester.pumpAndSettle ();
3334
+ expect (scrollController.offset, 0 );
3335
+
3336
+ // Overscroll is OK for (horizontal) trackpad gestures.
3337
+
3338
+ await tester.trackpadFling (find.byType (SingleChildScrollView ), const Offset (- 100 , 0 ), 500 );
3339
+ await tester.pumpAndSettle ();
3340
+ expect (scrollController.offset, greaterThan (100 ));
3341
+ scrollController.jumpTo (800 );
3342
+
3343
+ await tester.trackpadFling (find.byType (SingleChildScrollView ), const Offset (100 , 0 ), 500 );
3344
+ await tester.pumpAndSettle ();
3345
+ expect (scrollController.offset, lessThan (700 ));
3346
+ scrollController.jumpTo (0 );
3347
+
3348
+ }, variant: const TargetPlatformVariant (< TargetPlatform > {
3349
+ TargetPlatform .macOS,
3350
+ TargetPlatform .linux,
3351
+ TargetPlatform .windows,
3352
+ TargetPlatform .fuchsia,
3353
+ }));
3354
+
3355
+ testWidgets ('Desktop trackpad, nested ListViews, no explicit scrollbars, horizontal drag succeeds' , (WidgetTester tester) async {
3356
+ // Regression test for https://github.com/flutter/flutter/issues/150236.
3357
+ // This test is similar to "Desktop trackpad drag direction: -X,-Y...".
3358
+ // It's really only verifying that trackpad gestures are being handled
3359
+ // by the scrollable, not the scrollbar.
3360
+
3361
+ final Key outerListViewKey = UniqueKey ();
3362
+ final ScrollController scrollControllerY = ScrollController ();
3363
+ final ScrollController scrollControllerX = ScrollController ();
3364
+ addTearDown (scrollControllerY.dispose);
3365
+ addTearDown (scrollControllerX.dispose);
3366
+
3367
+ await tester.pumpWidget (
3368
+ Directionality (
3369
+ textDirection: TextDirection .ltr,
3370
+ child: MediaQuery (
3371
+ data: const MediaQueryData (),
3372
+ child: ListView (
3373
+ key: outerListViewKey,
3374
+ controller: scrollControllerY,
3375
+ children: < Widget > [
3376
+ const SizedBox (width: 200 , height: 200 ),
3377
+ SizedBox (
3378
+ height: 200 ,
3379
+ child: ListView ( // vertically centered within the 600 high viewport
3380
+ scrollDirection: Axis .horizontal,
3381
+ controller: scrollControllerX,
3382
+ children: List <Widget >.generate (5 , (int index) {
3383
+ return SizedBox (
3384
+ width: 200 ,
3385
+ child: Center (child: Text ('item $index ' )),
3386
+ );
3387
+ }),
3388
+ ),
3389
+ ),
3390
+ const SizedBox (width: 200 , height: 200 ),
3391
+ const SizedBox (width: 200 , height: 200 ),
3392
+ const SizedBox (width: 200 , height: 200 ),
3393
+ ],
3394
+ ),
3395
+ ),
3396
+ ),
3397
+ );
3398
+
3399
+ Finder outerListView () => find.byKey (outerListViewKey);
3400
+
3401
+ // 800x600 viewport content is 1000x1000
3402
+ expect (tester.getSize (outerListView ()), const Size (800 , 600 ));
3403
+ expect (scrollControllerY.offset, 0 );
3404
+ expect (scrollControllerY.position.maxScrollExtent, 400 );
3405
+ expect (scrollControllerX.offset, 0 );
3406
+ expect (scrollControllerX.position.maxScrollExtent, 200 );
3407
+
3408
+ // Vertical scrolling: -Y trackpad motion produces positive scroll offset change
3409
+ await tester.trackpadFling (outerListView (), const Offset (0 , - 600 ), 500 );
3410
+ await tester.pumpAndSettle ();
3411
+ expect (scrollControllerY.offset, 400 );
3412
+ await tester.trackpadFling (outerListView (), const Offset (0 , 600 ), 500 );
3413
+ await tester.pumpAndSettle ();
3414
+ expect (scrollControllerY.offset, 0 );
3415
+
3416
+ // Horizontal scrolling: -X trackpad motion produces positive scroll offset change
3417
+ await tester.trackpadFling (outerListView (), const Offset (- 800 , 0 ), 500 );
3418
+ await tester.pumpAndSettle ();
3419
+ expect (scrollControllerX.offset, 200 );
3420
+ await tester.trackpadFling (outerListView (), const Offset (800 , 0 ), 500 );
3421
+ await tester.pumpAndSettle ();
3422
+ expect (scrollControllerX.offset, 0 );
3423
+
3424
+ }, variant: const TargetPlatformVariant (< TargetPlatform > {
3425
+ TargetPlatform .macOS,
3426
+ TargetPlatform .linux,
3427
+ TargetPlatform .windows,
3428
+ TargetPlatform .fuchsia,
3429
+ }));
3430
+
3431
+ testWidgets ('Desktop trackpad, nested ListViews, no explicit scrollbars, horizontal drag succeeds' , (WidgetTester tester) async {
3432
+ // Regression test for https://github.com/flutter/flutter/issues/150342
3433
+
3434
+ final ScrollController scrollController = ScrollController ();
3435
+ addTearDown (scrollController.dispose);
3436
+
3437
+ late Size childSize;
3438
+ late StateSetter rebuildScrollViewChild;
3439
+
3440
+ Widget buildFrame (Axis scrollDirection) {
3441
+ return Directionality (
3442
+ textDirection: TextDirection .ltr,
3443
+ child: MediaQuery (
3444
+ data: const MediaQueryData (),
3445
+ child: RawScrollbar (
3446
+ controller: scrollController,
3447
+ child: SingleChildScrollView (
3448
+ controller: scrollController,
3449
+ scrollDirection: scrollDirection,
3450
+ child: StatefulBuilder (
3451
+ builder: (BuildContext context, StateSetter setState) {
3452
+ rebuildScrollViewChild = setState;
3453
+ return SizedBox (width: childSize.width, height: childSize.height);
3454
+ },
3455
+ ),
3456
+ ),
3457
+ ),
3458
+ ),
3459
+ );
3460
+ }
3461
+
3462
+ RawGestureDetector getScrollbarGestureDetector () {
3463
+ return tester.widget <RawGestureDetector >(
3464
+ find.descendant (of: find.byType (RawScrollbar ), matching: find.byType (RawGestureDetector )).first
3465
+ );
3466
+ }
3467
+
3468
+ // Vertical scrollDirection
3469
+
3470
+ childSize = const Size (800 , 600 );
3471
+ await tester.pumpWidget (buildFrame (Axis .vertical));
3472
+ // Scrolling isn't possible, so there are no scrollbar gesture recognizers.
3473
+ expect (getScrollbarGestureDetector ().gestures.length, 0 );
3474
+
3475
+ rebuildScrollViewChild (() { childSize = const Size (800 , 800 ); });
3476
+ await tester.pumpAndSettle ();
3477
+ // Scrolling is now possible, so there are scrollbar (thumb and track) gesture recognizers.
3478
+ expect (getScrollbarGestureDetector ().gestures.length, greaterThan (1 ));
3479
+
3480
+ // Horizontal scrollDirection
3481
+
3482
+ childSize = const Size (800 , 600 );
3483
+ await tester.pumpWidget (buildFrame (Axis .horizontal));
3484
+ await tester.pumpAndSettle ();
3485
+ // Scrolling isn't possible, so there are no scrollbar gesture recognizers.
3486
+ expect (getScrollbarGestureDetector ().gestures.length, 0 );
3487
+
3488
+ rebuildScrollViewChild (() { childSize = const Size (1000 , 600 ); });
3489
+ await tester.pumpAndSettle ();
3490
+ // Scrolling is now possible, so there are scrollbar (thumb and track) gesture recognizers.
3491
+ expect (getScrollbarGestureDetector ().gestures.length, greaterThan (1 ));
3258
3492
});
3259
3493
}
0 commit comments