Merge pull request #1449 from Hixie/drag-offset
Draggable offsets and fix default drag feedback
This commit is contained in:
commit
9a54c1bc7f
@ -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 {
|
|||||||
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);
|
|||||||
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 {
|
|||||||
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> {
|
|||||||
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>> {
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
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
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user