Skip to content

Add an additional builder to DragTarget which fires on every Draggabl…#60174

Merged
fluttergithubbot merged 1 commit into
flutter:masterfrom
monkeyswarm:DragTargetBuilder
Jul 28, 2020
Merged

Add an additional builder to DragTarget which fires on every Draggabl…#60174
fluttergithubbot merged 1 commit into
flutter:masterfrom
monkeyswarm:DragTargetBuilder

Conversation

@monkeyswarm

@monkeyswarm monkeyswarm commented Jun 24, 2020

Copy link
Copy Markdown
Contributor

…e movement within the DragTarget, and vends DragTargetDetails instead of Dragagble data.

Also adds an onMove callback on the DragTarget.

Description

-Adds an additional builder to DragTarget ("detailsBuilder") with a different signature. This additional builder is called on every move of a DragAvatar within the DragTarget, and vends DragTargetDetails (rather than just the raw data). This allows user to decide whether they want the existing behavior (rebuild on DragAvatar enter/leave/accept/reject), or additional behavior (rebuilt the same times as [builder], but also rebuilt on each move), in order to draw decorations for hovering draggables.
Note that the user must set either of the two builders; if both are set, the detailsBuilder is preferred and called.

-Adds an onMove callback, so that DragAvatar movement in the DragTarget can be handled outside of the build tree. This allows, for example, drawing outside the DragTarget or reporting movement to another widget.

Related Issues

Fixes #58982

Tests

I added the following tests:

Awaiting guidance on this design before adding additional tests to draggable_test (which will be part of this commit)

Checklist

Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes ([x]). This will ensure a smooth and quick review process.

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I signed the CLA.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I updated/added relevant documentation (doc comments with ///).
  • All existing and new tests are passing.
  • The analyzer (flutter analyze --flutter-repo) does not report any problems on my PR.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Did any tests fail when you ran them? Please read Handling breaking changes.

@fluttergithubbot fluttergithubbot added the framework flutter/packages/flutter repository. See also f: labels. label Jun 24, 2020
@fluttergithubbot

Copy link
Copy Markdown
Contributor

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@monkeyswarm

Copy link
Copy Markdown
Contributor Author

@HansMuller and/or @goderbauer PTAL (I can't seem to add reviewers). If the design is acceptable, I will add tests.

@dkwingsmt dkwingsmt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job, especially adding these documentations!

Most of the comments are bike shedding.

Comment thread packages/flutter/lib/src/widgets/drag_target.dart Outdated
Comment thread packages/flutter/lib/src/widgets/drag_target.dart Outdated
Comment thread packages/flutter/lib/src/widgets/drag_target.dart Outdated
Comment thread packages/flutter/lib/src/widgets/drag_target.dart Outdated
Comment thread packages/flutter/lib/src/widgets/drag_target.dart Outdated
Comment thread packages/flutter/lib/src/widgets/drag_target.dart Outdated
Comment thread packages/flutter/lib/src/widgets/drag_target.dart Outdated
Comment thread packages/flutter/lib/src/widgets/drag_target.dart Outdated
Comment thread packages/flutter/lib/src/widgets/drag_target.dart Outdated
@dkwingsmt

Copy link
Copy Markdown
Contributor

Also, I see the demonstration in #58982 seems to have a one-frame delay between the dragged square and child square. Does this implementation have the same issue?

Comment thread packages/flutter/lib/src/widgets/drag_target.dart Outdated
@monkeyswarm
monkeyswarm force-pushed the DragTargetBuilder branch 2 times, most recently from b9dddd5 to a3d3559 Compare July 1, 2020 21:34
@monkeyswarm

Copy link
Copy Markdown
Contributor Author

Also, I see the demonstration in #58982 seems to have a one-frame delay between the dragged square and child square. Does this implementation have the same issue?

It does not. The commit implementation does a rebuild on move (for immediate updating of children) and also the onMove callback (for logic outside of the build tree)

@goderbauer

Copy link
Copy Markdown
Member

Having those two different builder on the widget is a very strange API that I would like to avoid. It seems unnecessary confusing to the user. Hence my suggestion if you can do what you want to do by just adding the onMove callback.

@monkeyswarm

monkeyswarm commented Jul 9, 2020

Copy link
Copy Markdown
Contributor Author

Having those two different builder on the widget is a very strange API that I would like to avoid. It seems unnecessary confusing to the user. Hence my suggestion if you can do what you want to do by just adding the onMove callback.

I agree it's an unusual API. However, just using onMove() is not as ergonomic as something purely within a widget hierarchy. If I want to draw within the DragTarget while the Draggable moves, here's examples with the new callback, and with onMove:

Example of new detailedMovementBuilder, which has a more ergonomic tree of widgets, and could be used in both StatefulWidgets and StatelessWidgets

Widget build(_) =>
  ...
  child: DragTarget<int>(
    detailedMovementBuilder: (context, candidateDetails, rejectedDetails) => Stack(children:[
      if (candidateDetails.isNotEmpty)
        Positioned(...) // position based on candidateDetails
      )]);

Example with onMove, which now requires an additional piece of state and use of setState(), and thus only usable in StatefulWidgets

Offset _coords;

Widget build(_) =>
  ...
  child: DragTarget<int>(
    builder: (context, candidateData, rejectedData) =>Stack(children:[
      if (_coords != null)
        Positioned(...) // Layout based on value of _coords
      ]),
    onMove: (details) => setState(_coords = details.offset));

Quick discussion of an alternative, consisting of all the following

  1. A breaking change to [builder] which provides DragTargetDetails instead of 'T data'. The signature would effectively be the same signature as the new proposed detailedMovementBuilder:
typedef DragTargetDetailedMovementBuilder<T> =
    Widget Function(BuildContext context, List<DragTargetDetails<T>> candidateDetails, List<DragTargetDetails<dynamic>> rejectedDetails);

. However, it would continue to only fire child rebuilds on Draggable enter/leave/drop/reject.
2) A bool flag (e.g. 'rebuildOnMove') which changes the behavior of the builder from the default, to rebuilding on each move.
3) Still have an onMove() callback for logic outside of the local widget build phase
This gets all the needed functionality, plus ergonomic stateless code, without a second builder method.

Thanks for taking a look.

@goderbauer

Copy link
Copy Markdown
Member

I still think that just providing onMove is the best option here. It gives us a clean framework API without any user confucion and you can still do all the thinks you want to do.

@monkeyswarm

Copy link
Copy Markdown
Contributor Author

I've removed the additional builder function, and only added the onMove() callback. PTAL.

@goderbauer goderbauer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with one nit

Comment on lines 703 to 705

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe extract this out into a private method and call it below as well.

@goderbauer

Copy link
Copy Markdown
Member

Not sure why the doc shard is failing. Maybe try rebasing this onto the latest master and try again?

@monkeyswarm

Copy link
Copy Markdown
Contributor Author

Rebased on latest and more stuff is green. I don't know how to remove or resolve the requested review from @dkwingsmt, though.

@dkwingsmt

Copy link
Copy Markdown
Contributor

You're good to go with goderbauer's approval! :)

@fluttergithubbot

Copy link
Copy Markdown
Contributor

This pull request is not suitable for automatic merging in its current state.

  • This pull request has changes requested by @dkwingsmt. Please resolve those before re-applying the label.

@fluttergithubbot

Copy link
Copy Markdown
Contributor

This pull request is not suitable for automatic merging in its current state.

  • This pull request has changes requested by @dkwingsmt. Please resolve those before re-applying the label.

@dkwingsmt dkwingsmt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RSLGTM

@fluttergithubbot
fluttergithubbot merged commit 0fdb21f into flutter:master Jul 28, 2020
Pragya007 pushed a commit to Pragya007/flutter that referenced this pull request Aug 11, 2020
mingwandroid pushed a commit to mingwandroid/flutter that referenced this pull request Sep 6, 2020
@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Jul 30, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Get position of in-flight Draggables on a DragTarget

6 participants