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 {
|
||||
_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();
|
||||
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user