mirror of
https://github.com/flutter/flutter
synced 2024-07-16 10:29:14 +00:00
2DScrollView - Fix drag when one axis does not have enough content (#145566)
Fixes https://github.com/flutter/flutter/issues/144982 For reference, may have to do with #138442 when we reworked the gesture handling. The adjustments to the comments here were certainly from #138442 not updating them. Confused myself for a minute or two. ð
This commit is contained in:
parent
14774b95c2
commit
c5047e0ada
|
@ -1982,6 +1982,7 @@ class TwoDimensionalScrollableState extends State<TwoDimensionalScrollable> {
|
|||
viewportBuilder: (BuildContext context, ViewportOffset verticalOffset) {
|
||||
return _HorizontalInnerDimension(
|
||||
key: _horizontalInnerScrollableKey,
|
||||
verticalOuterKey: _verticalOuterScrollableKey,
|
||||
axisDirection: widget.horizontalDetails.direction,
|
||||
controller: widget.horizontalDetails.controller
|
||||
?? _horizontalFallbackController!,
|
||||
|
@ -2250,9 +2251,9 @@ class _VerticalOuterDimensionState extends ScrollableState {
|
|||
if (value) {
|
||||
// Replaces the typical vertical/horizontal drag gesture recognizers
|
||||
// with a pan gesture recognizer to allow bidirectional scrolling.
|
||||
// Based on the diagonalDragBehavior, valid horizontal deltas are
|
||||
// applied to this scrollable, while vertical deltas are routed to
|
||||
// the vertical scrollable.
|
||||
// Based on the diagonalDragBehavior, valid vertical deltas are
|
||||
// applied to this scrollable, while horizontal deltas are routed to
|
||||
// the horizontal scrollable.
|
||||
_gestureRecognizers = <Type, GestureRecognizerFactory>{
|
||||
PanGestureRecognizer: GestureRecognizerFactoryWithHandlers<PanGestureRecognizer>(
|
||||
() => PanGestureRecognizer(supportedDevices: _configuration.dragDevices),
|
||||
|
@ -2303,6 +2304,7 @@ class _VerticalOuterDimensionState extends ScrollableState {
|
|||
class _HorizontalInnerDimension extends Scrollable {
|
||||
const _HorizontalInnerDimension({
|
||||
super.key,
|
||||
required this.verticalOuterKey,
|
||||
required super.viewportBuilder,
|
||||
required super.axisDirection,
|
||||
super.controller,
|
||||
|
@ -2315,6 +2317,7 @@ class _HorizontalInnerDimension extends Scrollable {
|
|||
this.diagonalDragBehavior = DiagonalDragBehavior.none,
|
||||
}) : assert(axisDirection == AxisDirection.left || axisDirection == AxisDirection.right);
|
||||
|
||||
final GlobalKey<ScrollableState> verticalOuterKey;
|
||||
final DiagonalDragBehavior diagonalDragBehavior;
|
||||
|
||||
@override
|
||||
|
@ -2324,6 +2327,7 @@ class _HorizontalInnerDimension extends Scrollable {
|
|||
class _HorizontalInnerDimensionState extends ScrollableState {
|
||||
late ScrollableState verticalScrollable;
|
||||
|
||||
GlobalKey<ScrollableState> get verticalOuterKey => (widget as _HorizontalInnerDimension).verticalOuterKey;
|
||||
DiagonalDragBehavior get diagonalDragBehavior => (widget as _HorizontalInnerDimension).diagonalDragBehavior;
|
||||
|
||||
@override
|
||||
|
@ -2379,9 +2383,12 @@ class _HorizontalInnerDimensionState extends ScrollableState {
|
|||
case DiagonalDragBehavior.free:
|
||||
if (value) {
|
||||
// If a type of diagonal scrolling is enabled, a panning gesture
|
||||
// recognizer will be created for the _InnerDimension. So in this
|
||||
// case, the _OuterDimension does not require a gesture recognizer.
|
||||
// recognizer will be created for the _VerticalOuterDimension. So in
|
||||
// this case, the _HorizontalInnerDimension does not require a gesture
|
||||
// recognizer, meanwhile we should ensure the outer dimension has
|
||||
// updated in case it did not have enough content to enable dragging.
|
||||
_gestureRecognizers = const <Type, GestureRecognizerFactory>{};
|
||||
verticalOuterKey.currentState!.setCanDrag(value);
|
||||
// Cancel the active hold/drag (if any) because the gesture recognizers
|
||||
// will soon be disposed by our RawGestureDetector, and we won't be
|
||||
// receiving pointer up events to cancel the hold/drag.
|
||||
|
|
|
@ -580,5 +580,297 @@ void main() {
|
|||
expect(horizontalController.position.activity!.velocity, 0.0);
|
||||
expect(verticalController.position.activity!.velocity, 0.0);
|
||||
});
|
||||
|
||||
group('Can drag horizontally when there is not enough vertical content', () {
|
||||
testWidgets('DiagonalDragBehavior.free', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/144982
|
||||
final ScrollController verticalController = ScrollController();
|
||||
addTearDown(verticalController.dispose);
|
||||
final ScrollController horizontalController = ScrollController();
|
||||
addTearDown(horizontalController.dispose);
|
||||
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: SimpleBuilderTableView(
|
||||
verticalDetails: ScrollableDetails.vertical(controller: verticalController),
|
||||
horizontalDetails: ScrollableDetails.horizontal(controller: horizontalController),
|
||||
diagonalDragBehavior: DiagonalDragBehavior.free,
|
||||
delegate: TwoDimensionalChildBuilderDelegate(
|
||||
maxXIndex: 20,
|
||||
maxYIndex: 1,
|
||||
builder: _testChildBuilder,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, 0.0);
|
||||
expect(horizontalController.position.pixels, 0.0);
|
||||
expect(verticalController.position.maxScrollExtent, 0.0);
|
||||
expect(horizontalController.position.maxScrollExtent, 3400.0);
|
||||
// Fling vertically, nothing should happen.
|
||||
await tester.fling(
|
||||
find.byType(TwoDimensionalScrollable),
|
||||
const Offset(0.0, -200.0),
|
||||
2000.0,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, 0.0);
|
||||
expect(horizontalController.position.pixels, 0.0);
|
||||
// Fling horizontally, the horizontal position should change.
|
||||
await tester.fling(
|
||||
find.byType(TwoDimensionalScrollable),
|
||||
const Offset(-200.0, 0.0),
|
||||
2000.0,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, 0.0);
|
||||
expect(horizontalController.position.pixels, greaterThan(840.0));
|
||||
});
|
||||
|
||||
testWidgets('DiagonalDragBehavior.weightedEvent', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/144982
|
||||
final ScrollController verticalController = ScrollController();
|
||||
addTearDown(verticalController.dispose);
|
||||
final ScrollController horizontalController = ScrollController();
|
||||
addTearDown(horizontalController.dispose);
|
||||
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: SimpleBuilderTableView(
|
||||
verticalDetails: ScrollableDetails.vertical(controller: verticalController),
|
||||
horizontalDetails: ScrollableDetails.horizontal(controller: horizontalController),
|
||||
diagonalDragBehavior: DiagonalDragBehavior.weightedEvent,
|
||||
delegate: TwoDimensionalChildBuilderDelegate(
|
||||
maxXIndex: 20,
|
||||
maxYIndex: 1,
|
||||
builder: _testChildBuilder,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, 0.0);
|
||||
expect(horizontalController.position.pixels, 0.0);
|
||||
expect(verticalController.position.maxScrollExtent, 0.0);
|
||||
expect(horizontalController.position.maxScrollExtent, 3400.0);
|
||||
// Fling vertically, nothing should happen.
|
||||
await tester.fling(
|
||||
find.byType(TwoDimensionalScrollable),
|
||||
const Offset(0.0, -200.0),
|
||||
2000.0,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, 0.0);
|
||||
expect(horizontalController.position.pixels, 0.0);
|
||||
// Fling horizontally, the horizontal position should change.
|
||||
await tester.fling(
|
||||
find.byType(TwoDimensionalScrollable),
|
||||
const Offset(-200.0, 0.0),
|
||||
2000.0,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, 0.0);
|
||||
expect(horizontalController.position.pixels, greaterThan(840.0));
|
||||
});
|
||||
|
||||
testWidgets('DiagonalDragBehavior.weightedContinuous', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/144982
|
||||
final ScrollController verticalController = ScrollController();
|
||||
addTearDown(verticalController.dispose);
|
||||
final ScrollController horizontalController = ScrollController();
|
||||
addTearDown(horizontalController.dispose);
|
||||
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: SimpleBuilderTableView(
|
||||
verticalDetails: ScrollableDetails.vertical(controller: verticalController),
|
||||
horizontalDetails: ScrollableDetails.horizontal(controller: horizontalController),
|
||||
diagonalDragBehavior: DiagonalDragBehavior.weightedContinuous,
|
||||
delegate: TwoDimensionalChildBuilderDelegate(
|
||||
maxXIndex: 20,
|
||||
maxYIndex: 1,
|
||||
builder: _testChildBuilder,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, 0.0);
|
||||
expect(horizontalController.position.pixels, 0.0);
|
||||
expect(verticalController.position.maxScrollExtent, 0.0);
|
||||
expect(horizontalController.position.maxScrollExtent, 3400.0);
|
||||
// Fling vertically, nothing should happen.
|
||||
await tester.fling(
|
||||
find.byType(TwoDimensionalScrollable),
|
||||
const Offset(0.0, -200.0),
|
||||
2000.0,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, 0.0);
|
||||
expect(horizontalController.position.pixels, 0.0);
|
||||
// Fling horizontally, the horizontal position should change.
|
||||
await tester.fling(
|
||||
find.byType(TwoDimensionalScrollable),
|
||||
const Offset(-200.0, 0.0),
|
||||
2000.0,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, 0.0);
|
||||
expect(horizontalController.position.pixels, greaterThan(840.0));
|
||||
});
|
||||
});
|
||||
|
||||
group('Can drag vertically when there is not enough horizontal content', () {
|
||||
testWidgets('DiagonalDragBehavior.free', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/144982
|
||||
final ScrollController verticalController = ScrollController();
|
||||
addTearDown(verticalController.dispose);
|
||||
final ScrollController horizontalController = ScrollController();
|
||||
addTearDown(horizontalController.dispose);
|
||||
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: SimpleBuilderTableView(
|
||||
verticalDetails: ScrollableDetails.vertical(controller: verticalController),
|
||||
horizontalDetails: ScrollableDetails.horizontal(controller: horizontalController),
|
||||
diagonalDragBehavior: DiagonalDragBehavior.free,
|
||||
delegate: TwoDimensionalChildBuilderDelegate(
|
||||
maxXIndex: 1,
|
||||
maxYIndex: 20,
|
||||
builder: _testChildBuilder,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, 0.0);
|
||||
expect(horizontalController.position.pixels, 0.0);
|
||||
expect(verticalController.position.maxScrollExtent, 3600.0);
|
||||
expect(horizontalController.position.maxScrollExtent, 0.0);
|
||||
// Fling horizontally, nothing should happen.
|
||||
await tester.fling(
|
||||
find.byType(TwoDimensionalScrollable),
|
||||
const Offset(-200.0, 0.0),
|
||||
2000.0,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, 0.0);
|
||||
expect(horizontalController.position.pixels, 0.0);
|
||||
// Fling vertically, the vertical position should change.
|
||||
await tester.fling(
|
||||
find.byType(TwoDimensionalScrollable),
|
||||
const Offset(0.0, -200.0),
|
||||
2000.0,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, greaterThan(840.0));
|
||||
expect(horizontalController.position.pixels, 0.0);
|
||||
});
|
||||
|
||||
testWidgets('DiagonalDragBehavior.weightedEvent', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/144982
|
||||
final ScrollController verticalController = ScrollController();
|
||||
addTearDown(verticalController.dispose);
|
||||
final ScrollController horizontalController = ScrollController();
|
||||
addTearDown(horizontalController.dispose);
|
||||
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: SimpleBuilderTableView(
|
||||
verticalDetails: ScrollableDetails.vertical(controller: verticalController),
|
||||
horizontalDetails: ScrollableDetails.horizontal(controller: horizontalController),
|
||||
diagonalDragBehavior: DiagonalDragBehavior.weightedEvent,
|
||||
delegate: TwoDimensionalChildBuilderDelegate(
|
||||
maxXIndex: 1,
|
||||
maxYIndex: 20,
|
||||
builder: _testChildBuilder,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, 0.0);
|
||||
expect(horizontalController.position.pixels, 0.0);
|
||||
expect(verticalController.position.maxScrollExtent, 3600.0);
|
||||
expect(horizontalController.position.maxScrollExtent, 0.0);
|
||||
// Fling horizontally, nothing should happen.
|
||||
await tester.fling(
|
||||
find.byType(TwoDimensionalScrollable),
|
||||
const Offset(-200.0, 0.0),
|
||||
2000.0,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, 0.0);
|
||||
expect(horizontalController.position.pixels, 0.0);
|
||||
// Fling vertically, the vertical position should change.
|
||||
await tester.fling(
|
||||
find.byType(TwoDimensionalScrollable),
|
||||
const Offset(0.0, -200.0),
|
||||
2000.0,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, greaterThan(840.0));
|
||||
expect(horizontalController.position.pixels, 0.0);
|
||||
});
|
||||
|
||||
testWidgets('DiagonalDragBehavior.weightedContinuous', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/144982
|
||||
final ScrollController verticalController = ScrollController();
|
||||
addTearDown(verticalController.dispose);
|
||||
final ScrollController horizontalController = ScrollController();
|
||||
addTearDown(horizontalController.dispose);
|
||||
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: SimpleBuilderTableView(
|
||||
verticalDetails: ScrollableDetails.vertical(controller: verticalController),
|
||||
horizontalDetails: ScrollableDetails.horizontal(controller: horizontalController),
|
||||
diagonalDragBehavior: DiagonalDragBehavior.weightedContinuous,
|
||||
delegate: TwoDimensionalChildBuilderDelegate(
|
||||
maxXIndex: 1,
|
||||
maxYIndex: 20,
|
||||
builder: _testChildBuilder,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, 0.0);
|
||||
expect(horizontalController.position.pixels, 0.0);
|
||||
expect(verticalController.position.maxScrollExtent, 3600.0);
|
||||
expect(horizontalController.position.maxScrollExtent, 0.0);
|
||||
// Fling horizontally, nothing should happen.
|
||||
await tester.fling(
|
||||
find.byType(TwoDimensionalScrollable),
|
||||
const Offset(-200.0, 0.0),
|
||||
2000.0,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, 0.0);
|
||||
expect(horizontalController.position.pixels, 0.0);
|
||||
// Fling vertically, the vertical position should change.
|
||||
await tester.fling(
|
||||
find.byType(TwoDimensionalScrollable),
|
||||
const Offset(0.0, -200.0),
|
||||
2000.0,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(verticalController.position.pixels, greaterThan(840.0));
|
||||
expect(horizontalController.position.pixels, 0.0);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue