Skip to content

Commit

Permalink
Merge pull request #76 from karvulf/bugfix/scrolling-while-dragging
Browse files Browse the repository at this point in the history
Bugfix/scrolling while dragging
  • Loading branch information
karvulf committed May 24, 2023
2 parents afd20f3 + 93155f6 commit 8faf2ff
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 35 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,8 @@
## 5.0.0-dev.6
🐛 This release contains some bugfixes (optimization)
* while dragging there were issues when the user scrolled with another finger
* the dragged item was dropped if when it shouldn't

## 5.0.0-dev.5
🐛 This release contains some bugfixes
* fixed drag and drop after using functionality "scrolling while dragging" (thanks to [tsquillario](https://github.com/tsquillario) for pointing out that issue)
Expand Down
2 changes: 1 addition & 1 deletion example/lib/main.dart
Expand Up @@ -21,7 +21,7 @@ class MyApp extends StatefulWidget {
}

class _MyAppState extends State<MyApp> {
static const _startCounter = 33;
static const _startCounter = 3333;
final lockedIndices = <int>[];

int keyCounter = _startCounter;
Expand Down
12 changes: 11 additions & 1 deletion lib/controller/reorderable_drag_and_drop_controller.dart
Expand Up @@ -16,6 +16,10 @@ class ReorderableDragAndDropController extends ReorderableController {
/// After dragging a child, [_scrollOffset] is always updated.
Offset _scrollOffset = Offset.zero;

set scrollOffset(Offset offset) {
_scrollOffset = offset;
}

void handleDragStarted({
required ReorderableEntity reorderableEntity,
required Offset currentScrollOffset,
Expand Down Expand Up @@ -132,8 +136,14 @@ class ReorderableDragAndDropController extends ReorderableController {

if (!lockedIndices.contains(currentCollisionOrderId)) {
final collisionMapEntry = childrenOrderMap[currentCollisionOrderId];

// can happen if the collision item is still building
if (collisionMapEntry == null) {
return;
}

_updateCollision(
collisionReorderableEntity: collisionMapEntry!,
collisionReorderableEntity: collisionMapEntry,
lockedIndices: lockedIndices,
);
}
Expand Down
33 changes: 33 additions & 0 deletions lib/widgets/draggable_feedback.dart
@@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
import 'package:flutter_reorderable_grid_view/entities/reorderable_entity.dart';

class DraggableFeedback extends StatelessWidget {
final Widget child;
final ReorderableEntity reorderableEntity;
final Animation<Decoration> decoration;

const DraggableFeedback({
required this.child,
required this.reorderableEntity,
required this.decoration,
Key? key,
}) : super(key: key);

@override
Widget build(BuildContext context) {
final size = reorderableEntity.size;

return Material(
color: Colors.transparent, // removes white corners when having shadow
child: SizedBox(
height: size.height,
width: size.width,
child: DecoratedBoxTransition(
position: DecorationPosition.background,
decoration: decoration,
child: child,
),
),
);
}
}
14 changes: 11 additions & 3 deletions lib/widgets/reorderable_builder.dart
Expand Up @@ -228,7 +228,6 @@ class _ReorderableBuilderState extends State<ReorderableBuilder>
automaticScrollExtent: widget.automaticScrollExtent,
enableScrollingWhileDragging: widget.enableScrollingWhileDragging,
onDragUpdate: _handleDragUpdate,
onDragEnd: _handleDragEnd,
onScrollUpdate: _handleScrollUpdate,
getScrollOffset: _getScrollOffset,
child: child,
Expand Down Expand Up @@ -303,10 +302,12 @@ class _ReorderableBuilderState extends State<ReorderableBuilder>
dragChildBoxDecoration: widget.dragChildBoxDecoration,
onDragStarted: _handleDragStarted,
onDragEnd: (releasedReorderableEntity) {
// call to ensure animation to dropped item
_reorderableController.updateReleasedReorderableEntity(
releasedReorderableEntity: releasedReorderableEntity,
);
setState(() {});
_handleDragEnd();
},
child: child,
),
Expand All @@ -333,7 +334,11 @@ class _ReorderableBuilderState extends State<ReorderableBuilder>
pointerMoveEvent: pointerMoveEvent,
lockedIndices: widget.lockedIndices,
);
if (hasUpdated) setState(() {});
if (hasUpdated) {
// this fixes the issue when the user scrolls while dragging to get the updated scroll value
_reorderableController.scrollOffset = _getScrollOffset();
setState(() {});
}
}

void _handleScrollUpdate(Offset scrollOffset) {
Expand All @@ -344,7 +349,9 @@ class _ReorderableBuilderState extends State<ReorderableBuilder>

void _handleDragEnd() {
final draggedEntity = _reorderableController.draggedEntity;
widget.onDragEnd?.call(draggedEntity!.updatedOrderId);
if (draggedEntity == null) return;

widget.onDragEnd?.call(draggedEntity.updatedOrderId);

final reorderUpdateEntities = _reorderableController.handleDragEnd();

Expand All @@ -354,6 +361,7 @@ class _ReorderableBuilderState extends State<ReorderableBuilder>
reorderUpdateEntities: reorderUpdateEntities,
));
}

// important to update the dragged entity which should be null at this point
setState(() {});
}
Expand Down
44 changes: 24 additions & 20 deletions lib/widgets/reorderable_draggable.dart
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_reorderable_grid_view/entities/released_reorderable_entity.dart';
import 'package:flutter_reorderable_grid_view/entities/reorderable_entity.dart';
import 'package:flutter_reorderable_grid_view/utils/definitions.dart';
import 'package:flutter_reorderable_grid_view/widgets/draggable_feedback.dart';

/// Enables drag and drop behaviour for [child].
///
Expand Down Expand Up @@ -89,20 +90,13 @@ class _ReorderableDraggableState extends State<ReorderableDraggable>
Widget build(BuildContext context) {
final reorderableEntity = widget.reorderableEntity;
var child = widget.child;
final size = reorderableEntity.size;
final feedback = Material(
color: Colors.transparent, // removes white corners when having shadow
child: SizedBox(
height: size.height,
width: size.width,
child: DecoratedBoxTransition(
position: DecorationPosition.background,
decoration: _decorationTween.animate(
_decoratedBoxAnimationController,
),
child: child,
),

final feedback = DraggableFeedback(
reorderableEntity: reorderableEntity,
decoration: _decorationTween.animate(
_decoratedBoxAnimationController,
),
child: child,
);

final draggedKey = widget.currentDraggedEntity?.key;
Expand All @@ -123,18 +117,22 @@ class _ReorderableDraggableState extends State<ReorderableDraggable>
return LongPressDraggable(
delay: widget.longPressDelay,
onDragStarted: _handleDragStarted,
onDragEnd: _handleDragEnd,
onDraggableCanceled: (Velocity velocity, Offset offset) {
_handleDragEnd(offset);
},
feedback: feedback,
childWhenDragging: childWhenDragging,
child: childWhenDragging,
child: child,
);
} else {
return Draggable(
onDragStarted: _handleDragStarted,
onDragEnd: _handleDragEnd,
onDraggableCanceled: (Velocity velocity, Offset offset) {
_handleDragEnd(offset);
},
feedback: feedback,
childWhenDragging: childWhenDragging,
child: childWhenDragging,
child: child,
);
}
}
Expand All @@ -145,13 +143,19 @@ class _ReorderableDraggableState extends State<ReorderableDraggable>
_decoratedBoxAnimationController.forward();
}

void _handleDragEnd(DraggableDetails details) {
_decoratedBoxAnimationController.reset();
/// Called after dragging ends.
///
/// Important: This can also be called after the widget was disposed but
/// is still dragged. This has to be done to finish the drag and drop.
void _handleDragEnd(Offset offset) {
if (mounted) {
_decoratedBoxAnimationController.reset();
}

widget.onDragEnd(
ReleasedReorderableEntity(
reorderableEntity: widget.reorderableEntity,
dropOffset: details.offset,
dropOffset: offset,
),
);
}
Expand Down
9 changes: 0 additions & 9 deletions lib/widgets/reorderable_scrolling_listener.dart
Expand Up @@ -23,9 +23,6 @@ class ReorderableScrollingListener extends StatefulWidget {
/// Callback when the offset of the tapped area is changing.
final PointerMoveEventListener onDragUpdate;

/// Called after releasing the dragged child.
final VoidCallback onDragEnd;

/// Called when the current scrolling position changes.
final void Function(Offset scrollOffset) onScrollUpdate;

Expand All @@ -43,7 +40,6 @@ class ReorderableScrollingListener extends StatefulWidget {
required this.enableScrollingWhileDragging,
required this.automaticScrollExtent,
required this.onDragUpdate,
required this.onDragEnd,
required this.onScrollUpdate,
required this.getScrollOffset,
required this.reorderableChildKey,
Expand Down Expand Up @@ -94,11 +90,6 @@ class _ReorderableScrollingListenerState
_handleDragUpdate(details);
}
},
onPointerUp: (details) {
if (widget.isDragging) {
widget.onDragEnd();
}
},
child: widget.child,
);
}
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
@@ -1,6 +1,6 @@
name: flutter_reorderable_grid_view
description: Enables animated GridViews when updating children or when trying to reorder them by using drag and drop.
version: 5.0.0-dev.5
version: 5.0.0-dev.6
repository: https://github.com/karvulf/flutter-reorderable-grid-view

environment:
Expand Down

0 comments on commit 8faf2ff

Please sign in to comment.