Commit 894a1ca0 authored by Hixie's avatar Hixie

Draggable offsets and fix default drag feedback

You can now set an offset that will be used for the hit testing for
drops. (It doesn't move the feedback by default; use a Transform for
that.) I also made the default feedback not be Opacity 0.5 always.
parent dd6790fc
...@@ -50,13 +50,15 @@ class ExampleDragTargetState extends State<ExampleDragTarget> { ...@@ -50,13 +50,15 @@ class ExampleDragTargetState extends State<ExampleDragTarget> {
} }
class Dot extends StatelessComponent { class Dot extends StatelessComponent {
Dot({ Key key, this.color }): super(key: key); Dot({ Key key, this.color, this.size }): super(key: key);
final Color color; final Color color;
final double size;
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new Container( return new Container(
width: 50.0, width: size,
height: 50.0, height: size,
decoration: new BoxDecoration( decoration: new BoxDecoration(
borderRadius: 10.0,
backgroundColor: color backgroundColor: color
) )
); );
...@@ -68,12 +70,24 @@ class ExampleDragSource extends StatelessComponent { ...@@ -68,12 +70,24 @@ class ExampleDragSource extends StatelessComponent {
final NavigatorState navigator; final NavigatorState navigator;
final String name; final String name;
final Color color; final Color color;
static const kDotSize = 50.0;
static const kFingerSize = 50.0;
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new Draggable( return new Draggable(
navigator: navigator, navigator: navigator,
data: new DragData(name), data: new DragData(name),
child: new Dot(color: color), child: new Dot(color: color, size: kDotSize),
feedback: new Dot(color: color) feedback: new Transform(
transform: new Matrix4.identity()..translate(-kDotSize / 2.0, -(kDotSize / 2.0 + kFingerSize)),
child: new Opacity(
opacity: 0.75,
child: new Dot(color: color, size: kDotSize)
)
),
feedbackOffset: const Offset(0.0, -kFingerSize),
dragAnchor: DragAnchor.pointer
); );
} }
} }
......
...@@ -17,9 +17,38 @@ typedef void DragTargetAccept<T>(T data); ...@@ -17,9 +17,38 @@ typedef void DragTargetAccept<T>(T data);
typedef Widget DragTargetBuilder<T>(BuildContext context, List<T> candidateData, List<dynamic> rejectedData); typedef Widget DragTargetBuilder<T>(BuildContext context, List<T> candidateData, List<dynamic> rejectedData);
typedef void DragFinishedNotification(); typedef void DragFinishedNotification();
enum DragAnchor {
/// Display the feedback anchored at the position of the original child. If
/// feedback is identical to the child, then this means the feedback will
/// exactly overlap the original child when the drag starts.
child,
/// Display the feedback anchored at the position of the touch that started
/// the drag. If feedback is identical to the child, then this means the top
/// left of the feedback will be under the finger when the drag starts. This
/// will likely not exactly overlap the original child, e.g. if the child is
/// big and the touch was not centered. This mode is useful when the feedback
/// is transformed so as to move the feedback to the left by half its width,
/// and up by half its width plus the height of the finger, since then it
/// appears as if putting the finger down makes the touch feedback appear
/// above the finger. (It feels weird for it to appear offset from the
/// original child if it's anchored to the child and not the finger.)
pointer,
}
class Draggable extends StatefulComponent { class Draggable extends StatefulComponent {
Draggable({ Key key, this.navigator, this.data, this.child, this.feedback }): super(key: key) { Draggable({
Key key,
this.navigator,
this.data,
this.child,
this.feedback,
this.feedbackOffset: Offset.zero,
this.dragAnchor: DragAnchor.child
}): super(key: key) {
assert(navigator != null); assert(navigator != null);
assert(child != null);
assert(feedback != null);
} }
final NavigatorState navigator; final NavigatorState navigator;
...@@ -27,6 +56,12 @@ class Draggable extends StatefulComponent { ...@@ -27,6 +56,12 @@ class Draggable extends StatefulComponent {
final Widget child; final Widget child;
final Widget feedback; final Widget feedback;
/// The feedbackOffset can be used to set the hit test target point for the
/// purposes of finding a drag target. It is especially useful if the feedback
/// is transformed compared to the child.
final Offset feedbackOffset;
final DragAnchor dragAnchor;
DraggableState createState() => new DraggableState(); DraggableState createState() => new DraggableState();
} }
...@@ -36,12 +71,23 @@ class DraggableState extends State<Draggable> { ...@@ -36,12 +71,23 @@ class DraggableState extends State<Draggable> {
void _startDrag(sky.PointerEvent event) { void _startDrag(sky.PointerEvent event) {
if (_route != null) if (_route != null)
return; // TODO(ianh): once we switch to using gestures, just hand the gesture to the route so it can do everything itself. then we can have multiple drags at the same time. return; // TODO(ianh): once we switch to using gestures, just hand the gesture to the route so it can do everything itself. then we can have multiple drags at the same time.
Point point = new Point(event.x, event.y); final Point point = new Point(event.x, event.y);
RenderBox renderObject = context.findRenderObject(); Point dragStartPoint;
switch (config.dragAnchor) {
case DragAnchor.child:
final RenderBox renderObject = context.findRenderObject();
dragStartPoint = renderObject.globalToLocal(point);
break;
case DragAnchor.pointer:
dragStartPoint = Point.origin;
break;
}
assert(dragStartPoint != null);
_route = new DragRoute( _route = new DragRoute(
data: config.data, data: config.data,
dragStartPoint: renderObject.globalToLocal(point), dragStartPoint: dragStartPoint,
feedback: config.feedback, feedback: config.feedback,
feedbackOffset: config.feedbackOffset,
onDragFinished: () { onDragFinished: () {
_route = null; _route = null;
} }
...@@ -149,11 +195,20 @@ class DragTargetState<T> extends State<DragTarget<T>> { ...@@ -149,11 +195,20 @@ class DragTargetState<T> extends State<DragTarget<T>> {
enum DragEndKind { dropped, canceled } enum DragEndKind { dropped, canceled }
class DragRoute extends Route { class DragRoute extends Route {
DragRoute({ this.data, this.dragStartPoint: Point.origin, this.feedback, this.onDragFinished }); DragRoute({
this.data,
this.dragStartPoint: Point.origin,
this.feedback,
this.feedbackOffset: Offset.zero,
this.onDragFinished
}) {
assert(feedbackOffset != null);
}
final dynamic data; final dynamic data;
final Point dragStartPoint; final Point dragStartPoint;
final Widget feedback; final Widget feedback;
final Offset feedbackOffset;
final DragFinishedNotification onDragFinished; final DragFinishedNotification onDragFinished;
DragTargetState _activeTarget; DragTargetState _activeTarget;
...@@ -162,7 +217,7 @@ class DragRoute extends Route { ...@@ -162,7 +217,7 @@ class DragRoute extends Route {
void update(Point globalPosition) { void update(Point globalPosition) {
_lastOffset = globalPosition - dragStartPoint; _lastOffset = globalPosition - dragStartPoint;
HitTestResult result = WidgetFlutterBinding.instance.hitTest(globalPosition); HitTestResult result = WidgetFlutterBinding.instance.hitTest(globalPosition + feedbackOffset);
DragTargetState target = _getDragTarget(result.path); DragTargetState target = _getDragTarget(result.path);
if (target == _activeTarget) if (target == _activeTarget)
return; return;
...@@ -208,10 +263,7 @@ class DragRoute extends Route { ...@@ -208,10 +263,7 @@ class DragRoute extends Route {
left: _lastOffset.dx, left: _lastOffset.dx,
top: _lastOffset.dy, top: _lastOffset.dy,
child: new IgnorePointer( child: new IgnorePointer(
child: new Opacity( child: feedback
opacity: 0.5,
child: feedback
)
) )
); );
} }
......
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