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';
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'basic.dart';
import 'debug.dart';
......@@ -521,6 +522,15 @@ class SliverReorderableListState extends State<SliverReorderableList> with Ticke
Offset? _finalDropPosition;
MultiDragGestureRecognizer? _recognizer;
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;
Axis get _scrollDirection => axisDirectionToAxis(_scrollable.axisDirection);
......@@ -615,6 +625,10 @@ class SliverReorderableListState extends State<SliverReorderableList> with Ticke
final _ReorderableItemState item = _items[_dragIndex!]!;
item.dragging = true;
item.rebuild();
_dragStartTransitionComplete = false;
SchedulerBinding.instance!.addPostFrameCallback((Duration duration) {
_dragStartTransitionComplete = true;
});
_insertIndex = item.index;
_dragInfo = _DragInfo(
......@@ -722,7 +736,14 @@ class SliverReorderableListState extends State<SliverReorderableList> with Ticke
if (item.index == _dragIndex! || !item.mounted)
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 itemExtent = _scrollDirection == Axis.vertical ? geometry.height : geometry.width;
final double itemEnd = itemStart + itemExtent;
......
......@@ -122,7 +122,7 @@ void main() {
expect(items, orderedEquals(<int>[0, 1, 2, 3, 4, 5, 6, 7]));
// 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]);
expect(tester.getTopLeft(find.text('item 1')), Offset.zero);
expect(tester.getTopLeft(find.text('item 0')), const Offset(0, 100));
......@@ -136,7 +136,7 @@ void main() {
expect(items, orderedEquals(<int>[0, 1, 2, 3, 4, 5, 6, 7]));
// 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]);
expect(tester.getTopLeft(find.text('item 0')), Offset.zero);
expect(tester.getTopLeft(find.text('item 1')), const Offset(0, 300));
......@@ -433,7 +433,7 @@ void main() {
await tester.pump(kPressTimeout);
// 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 drag.up();
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