Merge pull request #1849 from Hixie/drag-horiz
Horizontal and Vertical Draggables
This commit is contained in:
commit
c0c2277767
@ -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 {
|
class _DelayedPointerState extends MultiDragPointerState {
|
||||||
_DelayedPointerState(Point initialPosition, Duration delay) : super(initialPosition) {
|
_DelayedPointerState(Point initialPosition, Duration delay) : super(initialPosition) {
|
||||||
assert(delay != null);
|
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.
|
/// Makes its child draggable starting from long press.
|
||||||
class LongPressDraggable<T> extends DraggableBase<T> {
|
class LongPressDraggable<T> extends DraggableBase<T> {
|
||||||
LongPressDraggable({
|
LongPressDraggable({
|
||||||
|
@ -338,6 +338,232 @@ void main() {
|
|||||||
tester.dispatchEvent(pointer.up(), firstLocation);
|
tester.dispatchEvent(pointer.up(), firstLocation);
|
||||||
tester.pump();
|
tester.pump();
|
||||||
expect(events, equals(<String>['drop']));
|
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();
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user