Commit 19a2f5ef authored by Hixie's avatar Hixie

Horizontal and Vertical Draggables

parent 19e51b96
......@@ -252,6 +252,61 @@ class ImmediateMultiDragGestureRecognizer extends MultiDragGestureRecognizer<_Im
}
}
class _HorizontalPointerState extends MultiDragPointerState {
_HorizontalPointerState(Point initialPosition) : super(initialPosition);
void checkForResolutionAfterMove() {
assert(pendingDelta != null);
if (pendingDelta.dx.abs() > kTouchSlop)
resolve(GestureDisposition.accepted);
}
void accepted(GestureMultiDragStartCallback starter) {
starter(initialPosition);
}
}
class HorizontalMultiDragGestureRecognizer extends MultiDragGestureRecognizer<_HorizontalPointerState> {
HorizontalMultiDragGestureRecognizer({
PointerRouter pointerRouter,
GestureArena gestureArena,
GestureMultiDragStartCallback onStart
}) : super(pointerRouter: pointerRouter, gestureArena: gestureArena, onStart: onStart);
_HorizontalPointerState createNewPointerState(PointerDownEvent event) {
return new _HorizontalPointerState(event.position);
}
}
class _VerticalPointerState extends MultiDragPointerState {
_VerticalPointerState(Point initialPosition) : super(initialPosition);
void checkForResolutionAfterMove() {
assert(pendingDelta != null);
if (pendingDelta.dy.abs() > kTouchSlop)
resolve(GestureDisposition.accepted);
}
void accepted(GestureMultiDragStartCallback starter) {
starter(initialPosition);
}
}
class VerticalMultiDragGestureRecognizer extends MultiDragGestureRecognizer<_VerticalPointerState> {
VerticalMultiDragGestureRecognizer({
PointerRouter pointerRouter,
GestureArena gestureArena,
GestureMultiDragStartCallback onStart
}) : super(pointerRouter: pointerRouter, gestureArena: gestureArena, onStart: onStart);
_VerticalPointerState createNewPointerState(PointerDownEvent event) {
return new _VerticalPointerState(event.position);
}
}
class _DelayedPointerState extends MultiDragPointerState {
_DelayedPointerState(Point initialPosition, Duration delay) : super(initialPosition) {
assert(delay != null);
......
......@@ -118,6 +118,70 @@ class Draggable<T> extends DraggableBase<T> {
}
}
/// Makes its child draggable. When competing with other gestures,
/// this will only start the drag horizontally.
class HorizontalDraggable<T> extends DraggableBase<T> {
HorizontalDraggable({
Key key,
T data,
Widget child,
Widget childWhenDragging,
Widget feedback,
Offset feedbackOffset: Offset.zero,
DragAnchor dragAnchor: DragAnchor.child,
int maxSimultaneousDrags
}) : super(
key: key,
data: data,
child: child,
childWhenDragging: childWhenDragging,
feedback: feedback,
feedbackOffset: feedbackOffset,
dragAnchor: dragAnchor,
maxSimultaneousDrags: maxSimultaneousDrags
);
MultiDragGestureRecognizer createRecognizer(PointerRouter router, GestureArena arena, GestureMultiDragStartCallback starter) {
return new HorizontalMultiDragGestureRecognizer(
pointerRouter: router,
gestureArena: arena,
onStart: starter
);
}
}
/// Makes its child draggable. When competing with other gestures,
/// this will only start the drag vertically.
class VerticalDraggable<T> extends DraggableBase<T> {
VerticalDraggable({
Key key,
T data,
Widget child,
Widget childWhenDragging,
Widget feedback,
Offset feedbackOffset: Offset.zero,
DragAnchor dragAnchor: DragAnchor.child,
int maxSimultaneousDrags
}) : super(
key: key,
data: data,
child: child,
childWhenDragging: childWhenDragging,
feedback: feedback,
feedbackOffset: feedbackOffset,
dragAnchor: dragAnchor,
maxSimultaneousDrags: maxSimultaneousDrags
);
MultiDragGestureRecognizer createRecognizer(PointerRouter router, GestureArena arena, GestureMultiDragStartCallback starter) {
return new VerticalMultiDragGestureRecognizer(
pointerRouter: router,
gestureArena: arena,
onStart: starter
);
}
}
/// Makes its child draggable starting from long press.
class LongPressDraggable<T> extends DraggableBase<T> {
LongPressDraggable({
......
......@@ -338,6 +338,232 @@ void main() {
tester.dispatchEvent(pointer.up(), firstLocation);
tester.pump();
expect(events, equals(<String>['drop']));
});
});
test('Drag and drop - horizontal and vertical draggables in vertical block', () {
testWidgets((WidgetTester tester) {
TestPointer pointer = new TestPointer(7);
List<String> events = <String>[];
Point firstLocation, secondLocation, thirdLocation;
tester.pumpWidget(new MaterialApp(
routes: <String, RouteBuilder>{
'/': (RouteArguments args) {
return new Block(
children: <Widget>[
new DragTarget(
builder: (context, data, rejects) {
return new Text('Target');
},
onAccept: (data) {
events.add('drop $data');
}
),
new Container(height: 400.0),
new HorizontalDraggable(
data: 1,
child: new Text('H'),
feedback: new Text('Dragging')
),
new VerticalDraggable(
data: 2,
child: new Text('V'),
feedback: new Text('Dragging')
),
new Container(height: 500.0),
new Container(height: 500.0),
new Container(height: 500.0),
new Container(height: 500.0),
]
);
},
}
));
expect(events, isEmpty);
expect(tester.findText('Target'), isNotNull);
expect(tester.findText('H'), isNotNull);
expect(tester.findText('V'), isNotNull);
// vertical draggable drags vertically
expect(events, isEmpty);
firstLocation = tester.getCenter(tester.findText('V'));
secondLocation = tester.getCenter(tester.findText('Target'));
tester.dispatchEvent(pointer.down(firstLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.move(secondLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.up(), firstLocation);
tester.pump();
expect(events, equals(<String>['drop 2']));
expect(tester.getCenter(tester.findText('Target')).y, greaterThan(0.0));
events.clear();
// horizontal draggable drags horizontally
expect(events, isEmpty);
firstLocation = tester.getTopLeft(tester.findText('H'));
secondLocation = tester.getTopRight(tester.findText('H'));
thirdLocation = tester.getCenter(tester.findText('Target'));
tester.dispatchEvent(pointer.down(firstLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.move(secondLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.move(thirdLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.up(), firstLocation);
tester.pump();
expect(events, equals(<String>['drop 1']));
expect(tester.getCenter(tester.findText('Target')).y, greaterThan(0.0));
events.clear();
// vertical draggable drags horizontally when there's no competition
// from other gesture detectors
expect(events, isEmpty);
firstLocation = tester.getTopLeft(tester.findText('V'));
secondLocation = tester.getTopRight(tester.findText('V'));
thirdLocation = tester.getCenter(tester.findText('Target'));
tester.dispatchEvent(pointer.down(firstLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.move(secondLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.move(thirdLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.up(), firstLocation);
tester.pump();
expect(events, equals(<String>['drop 2']));
expect(tester.getCenter(tester.findText('Target')).y, greaterThan(0.0));
events.clear();
// horizontal draggable doesn't drag vertically when there is competition
// for vertical gestures
expect(events, isEmpty);
firstLocation = tester.getCenter(tester.findText('H'));
secondLocation = tester.getCenter(tester.findText('Target'));
tester.dispatchEvent(pointer.down(firstLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.move(secondLocation), firstLocation);
tester.pump(); // scrolls off screen!
tester.dispatchEvent(pointer.up(), firstLocation);
tester.pump();
expect(events, equals(<String>[]));
expect(tester.getCenter(tester.findText('Target')).y, lessThan(0.0));
events.clear();
});
});
test('Drag and drop - horizontal and vertical draggables in horizontal block', () {
testWidgets((WidgetTester tester) {
TestPointer pointer = new TestPointer(7);
List<String> events = <String>[];
Point firstLocation, secondLocation, thirdLocation;
tester.pumpWidget(new MaterialApp(
routes: <String, RouteBuilder>{
'/': (RouteArguments args) {
return new Block(
scrollDirection: Axis.horizontal,
children: <Widget>[
new DragTarget(
builder: (context, data, rejects) {
return new Text('Target');
},
onAccept: (data) {
events.add('drop $data');
}
),
new Container(width: 400.0),
new HorizontalDraggable(
data: 1,
child: new Text('H'),
feedback: new Text('Dragging')
),
new VerticalDraggable(
data: 2,
child: new Text('V'),
feedback: new Text('Dragging')
),
new Container(width: 500.0),
new Container(width: 500.0),
new Container(width: 500.0),
new Container(width: 500.0),
]
);
},
}
));
expect(events, isEmpty);
expect(tester.findText('Target'), isNotNull);
expect(tester.findText('H'), isNotNull);
expect(tester.findText('V'), isNotNull);
// horizontal draggable drags horizontally
expect(events, isEmpty);
firstLocation = tester.getCenter(tester.findText('H'));
secondLocation = tester.getCenter(tester.findText('Target'));
tester.dispatchEvent(pointer.down(firstLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.move(secondLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.up(), firstLocation);
tester.pump();
expect(events, equals(<String>['drop 1']));
expect(tester.getCenter(tester.findText('Target')).x, greaterThan(0.0));
events.clear();
// vertical draggable drags vertically
expect(events, isEmpty);
firstLocation = tester.getTopLeft(tester.findText('V'));
secondLocation = tester.getBottomLeft(tester.findText('V'));
thirdLocation = tester.getCenter(tester.findText('Target'));
tester.dispatchEvent(pointer.down(firstLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.move(secondLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.move(thirdLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.up(), firstLocation);
tester.pump();
expect(events, equals(<String>['drop 2']));
expect(tester.getCenter(tester.findText('Target')).x, greaterThan(0.0));
events.clear();
// horizontal draggable drags vertically when there's no competition
// from other gesture detectors
expect(events, isEmpty);
firstLocation = tester.getTopLeft(tester.findText('H'));
secondLocation = tester.getBottomLeft(tester.findText('H'));
thirdLocation = tester.getCenter(tester.findText('Target'));
tester.dispatchEvent(pointer.down(firstLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.move(secondLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.move(thirdLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.up(), firstLocation);
tester.pump();
expect(events, equals(<String>['drop 1']));
expect(tester.getCenter(tester.findText('Target')).x, greaterThan(0.0));
events.clear();
// vertical draggable doesn't drag horizontally when there is competition
// for horizontal gestures
expect(events, isEmpty);
firstLocation = tester.getCenter(tester.findText('V'));
secondLocation = tester.getCenter(tester.findText('Target'));
tester.dispatchEvent(pointer.down(firstLocation), firstLocation);
tester.pump();
tester.dispatchEvent(pointer.move(secondLocation), firstLocation);
tester.pump(); // scrolls off screen!
tester.dispatchEvent(pointer.up(), firstLocation);
tester.pump();
expect(events, equals(<String>[]));
expect(tester.getCenter(tester.findText('Target')).x, lessThan(0.0));
events.clear();
});
});
......
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