blob: d51e3efc57293246db2293f755567fabae16cf87 [file] [log] [blame]
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
class TestResult {
bool dragStarted = false;
bool dragUpdate = false;
}
class NestedScrollableCase extends StatefulWidget {
const NestedScrollableCase({super.key, required this.testResult});
final TestResult testResult;
@override
State<NestedScrollableCase> createState() => _NestedScrollableCaseState();
}
class _NestedScrollableCaseState extends State<NestedScrollableCase> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverFixedExtentList(
itemExtent: 50.0,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onVerticalDragDown: (DragDownDetails details) {
widget.testResult.dragStarted = true;
},
onVerticalDragUpdate: (DragUpdateDetails details){
widget.testResult.dragUpdate = true;
},
onVerticalDragEnd: (_) {},
child: Text('List Item $index', key: ValueKey<int>(index),
),
),
);
},
),
),
],
),
);
}
}
class NestedDragableCase extends StatefulWidget {
const NestedDragableCase({super.key, required this.testResult});
final TestResult testResult;
@override
State<NestedDragableCase> createState() => _NestedDragableCaseState();
}
class _NestedDragableCaseState extends State<NestedDragableCase> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverFixedExtentList(
itemExtent: 50.0,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
child: Draggable<Object>(
key: ValueKey<int>(index),
feedback: const Text('Dragging'),
child: Text('List Item $index'),
onDragStarted: () {
widget.testResult.dragStarted = true;
},
onDragUpdate: (DragUpdateDetails details){
widget.testResult.dragUpdate = true;
},
onDragEnd: (_) {},
),
);
},
),
),
],
),
);
}
}
void main() {
testWidgets('Scroll Views get the same ScrollConfiguration as GestureDetectors', (WidgetTester tester) async {
tester.binding.window.viewConfigurationTestValue = const ui.ViewConfiguration(
gestureSettings: ui.GestureSettings(physicalTouchSlop: 4),
);
final TestResult result = TestResult();
await tester.pumpWidget(MaterialApp(
title: 'Scroll Bug',
home: NestedScrollableCase(testResult: result),
));
// By dragging the scroll view more than the configured touch slop above but less than
// the framework default value, we demonstrate that this causes gesture detectors
// that do not receive the same gesture settings to fire at different times than would
// be expected.
final Offset start = tester.getCenter(find.byKey(const ValueKey<int>(1)));
await tester.timedDragFrom(start, const Offset(0, 5), const Duration(milliseconds: 50));
await tester.pumpAndSettle();
expect(result.dragStarted, true);
expect(result.dragUpdate, true);
});
testWidgets('Scroll Views get the same ScrollConfiguration as Draggables', (WidgetTester tester) async {
tester.binding.window.viewConfigurationTestValue = const ui.ViewConfiguration(
gestureSettings: ui.GestureSettings(physicalTouchSlop: 4),
);
final TestResult result = TestResult();
await tester.pumpWidget(MaterialApp(
title: 'Scroll Bug',
home: NestedDragableCase(testResult: result),
));
// By dragging the scroll view more than the configured touch slop above but less than
// the framework default value, we demonstrate that this causes gesture detectors
// that do not receive the same gesture settings to fire at different times than would
// be expected.
final Offset start = tester.getCenter(find.byKey(const ValueKey<int>(1)));
await tester.timedDragFrom(start, const Offset(0, 5), const Duration(milliseconds: 50));
await tester.pumpAndSettle();
expect(result.dragStarted, true);
expect(result.dragUpdate, true);
});
}