Unverified Commit 7903370b authored by Darren Austin's avatar Darren Austin Committed by GitHub

Fixed a problem with the first drag update on a reorderable list. (#82296)

parent 3445cb86
...@@ -6,6 +6,7 @@ import 'dart:math'; ...@@ -6,6 +6,7 @@ import 'dart:math';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'basic.dart'; import 'basic.dart';
import 'debug.dart'; import 'debug.dart';
...@@ -521,6 +522,15 @@ class SliverReorderableListState extends State<SliverReorderableList> with Ticke ...@@ -521,6 +522,15 @@ class SliverReorderableListState extends State<SliverReorderableList> with Ticke
Offset? _finalDropPosition; Offset? _finalDropPosition;
MultiDragGestureRecognizer? _recognizer; MultiDragGestureRecognizer? _recognizer;
bool _autoScrolling = false; bool _autoScrolling = false;
// To implement the gap for the dragged item, we replace the dragged item
// with a zero sized box, and then translate all of the later items down
// by the size of the dragged item. This allows us to keep the order of the
// list, while still being able to animate the gap between the items. However
// for the first frame of the drag, the item has not yet been replaced, so
// the calculation for the gap is off by the size of the gap. This flag is
// used to determine if the transition to the zero sized box has completed,
// so the gap calculation can compensate for it.
bool _dragStartTransitionComplete = false;
late ScrollableState _scrollable; late ScrollableState _scrollable;
Axis get _scrollDirection => axisDirectionToAxis(_scrollable.axisDirection); Axis get _scrollDirection => axisDirectionToAxis(_scrollable.axisDirection);
...@@ -615,6 +625,10 @@ class SliverReorderableListState extends State<SliverReorderableList> with Ticke ...@@ -615,6 +625,10 @@ class SliverReorderableListState extends State<SliverReorderableList> with Ticke
final _ReorderableItemState item = _items[_dragIndex!]!; final _ReorderableItemState item = _items[_dragIndex!]!;
item.dragging = true; item.dragging = true;
item.rebuild(); item.rebuild();
_dragStartTransitionComplete = false;
SchedulerBinding.instance!.addPostFrameCallback((Duration duration) {
_dragStartTransitionComplete = true;
});
_insertIndex = item.index; _insertIndex = item.index;
_dragInfo = _DragInfo( _dragInfo = _DragInfo(
...@@ -722,7 +736,14 @@ class SliverReorderableListState extends State<SliverReorderableList> with Ticke ...@@ -722,7 +736,14 @@ class SliverReorderableListState extends State<SliverReorderableList> with Ticke
if (item.index == _dragIndex! || !item.mounted) if (item.index == _dragIndex! || !item.mounted)
continue; continue;
final Rect geometry = item.targetGeometry(); Rect geometry = item.targetGeometry();
if (!_dragStartTransitionComplete && _dragIndex! <= item.index) {
// Transition is not complete, so each item after the dragged item is still
// in its normal location and not moved up for the zero sized box that will
// replace the dragged item.
final Offset transitionOffset = _extentOffset(_reverse ? -gapExtent : gapExtent, _scrollDirection);
geometry = (geometry.topLeft - transitionOffset) & geometry.size;
}
final double itemStart = _scrollDirection == Axis.vertical ? geometry.top : geometry.left; final double itemStart = _scrollDirection == Axis.vertical ? geometry.top : geometry.left;
final double itemExtent = _scrollDirection == Axis.vertical ? geometry.height : geometry.width; final double itemExtent = _scrollDirection == Axis.vertical ? geometry.height : geometry.width;
final double itemEnd = itemStart + itemExtent; final double itemEnd = itemStart + itemExtent;
......
...@@ -122,7 +122,7 @@ void main() { ...@@ -122,7 +122,7 @@ void main() {
expect(items, orderedEquals(<int>[0, 1, 2, 3, 4, 5, 6, 7])); expect(items, orderedEquals(<int>[0, 1, 2, 3, 4, 5, 6, 7]));
// Drag item 0 downwards more than halfway to displace item 1. // Drag item 0 downwards more than halfway to displace item 1.
await pressDragRelease(tester.getCenter(find.text('item 0')), const Offset(0, 151)); await pressDragRelease(tester.getCenter(find.text('item 0')), const Offset(0, 51));
check(visible: <int>[0, 1, 2, 3, 4, 5], hidden: <int>[6, 7]); check(visible: <int>[0, 1, 2, 3, 4, 5], hidden: <int>[6, 7]);
expect(tester.getTopLeft(find.text('item 1')), Offset.zero); expect(tester.getTopLeft(find.text('item 1')), Offset.zero);
expect(tester.getTopLeft(find.text('item 0')), const Offset(0, 100)); expect(tester.getTopLeft(find.text('item 0')), const Offset(0, 100));
...@@ -136,7 +136,7 @@ void main() { ...@@ -136,7 +136,7 @@ void main() {
expect(items, orderedEquals(<int>[0, 1, 2, 3, 4, 5, 6, 7])); expect(items, orderedEquals(<int>[0, 1, 2, 3, 4, 5, 6, 7]));
// Drag item 1 to item 3 // Drag item 1 to item 3
await pressDragRelease(tester.getCenter(find.text('item 1')), const Offset(0, 251)); await pressDragRelease(tester.getCenter(find.text('item 1')), const Offset(0, 151));
check(visible: <int>[0, 1, 2, 3, 4, 5], hidden: <int>[6, 7]); check(visible: <int>[0, 1, 2, 3, 4, 5], hidden: <int>[6, 7]);
expect(tester.getTopLeft(find.text('item 0')), Offset.zero); expect(tester.getTopLeft(find.text('item 0')), Offset.zero);
expect(tester.getTopLeft(find.text('item 1')), const Offset(0, 300)); expect(tester.getTopLeft(find.text('item 1')), const Offset(0, 300));
...@@ -433,7 +433,7 @@ void main() { ...@@ -433,7 +433,7 @@ void main() {
await tester.pump(kPressTimeout); await tester.pump(kPressTimeout);
// Drag enough to move down the first item // Drag enough to move down the first item
await drag.moveBy(const Offset(0, 150)); await drag.moveBy(const Offset(0, 50));
await tester.pump(); await tester.pump();
await drag.up(); await drag.up();
await tester.pumpAndSettle(); await tester.pumpAndSettle();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment