Skip to content

Expose drop offset in DragTarget #55184

@monkeyswarm

Description

@monkeyswarm

Internal: b/154002938

Use case: user drags a Draggable from one widget to another widget, and needs to know where within the latter widget's DragTarget the drop occurred. The former widget may not still be mounted at this point.

Request: expose the drop offset value on the DragTarget.

Right now, when a Draggable's 'feedback' is dropped on a DropTarget:

  1. The drop target is asked whether to accept the Draggable.data via [onWillAccept], then calls [onAccept]
  2. The Draggable, if it is still mounted, calls [onDragEnd] with the global drop position

My use case is to drag a Draggable from one widget, to a separate widget, and drop; we need to know the position within the DragTarget in order to align the post-drop child in the latter widget.

I currently have a hacky workaround to do this: DragTarget.onAccept() stashes the Draggable.data in a temporary variable, and then Draggable.onDragEnd creates another variable (a tuple of the data and the position), and sets it as the value of a top-level ValueNotifier. Every single DragTarget will receive that notifier value and decide whether to complete the action with knowledge of a position.

That hacky workaround breaks if the widget with the Draggable is no longer mounted, since Draggable.onDragEnd (with its payload of the drop offset) is never called. Since Draggable.onDragEnd is the only place where the drop offset is exposed, this is an issue.

A few possibilities come to mind

  1. Modify Draggable.onDragEnd so that it will fire even if the widget is no longer mounted. In my cursory reading of drag_target.dart, I don't see a technical reason why the original widget must still be mounted in order for a caller to receive the offset data.
    So drag_target.dart line 399 is changed from
    if (mounted && widget.onDragEnd != null) {
    to
    if ( widget.onDragEnd != null) {
    This at least keeps my hack working, but I'd rather get a true fix, and remove our hack, by exposing the position on DragTarget.

  2. Expose the drop offset to DragTarget as part of DragTarget.onAccept(). This is an API signature change (of typedef DragTargetAccept) from
    void Function(T data)
    to
    void Function(T data, Offset offset)
    Since this is a breaking change, I'm assuming this is not preferred. (Or is there a way to make this a non-breaking change?)

  3. Expose the drop offset to DragTarget as a new callback (e.g. DragTarget.onDropPosition(Offset) or DragTarget.onAcceptPosition(Offset))

Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    c: proposalA detailed proposal for a change to Flutterframeworkflutter/packages/flutter repository. See also f: labels.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions