Fix asserts in Draggable dismounting (#4644)
In writing a test for #1927, I found a number of bugs in how Draggable shuts down. Previously it would leak its recongizer. Now it disposes its recognizer and the recognizer knows how to be disposed cleanly. Fixes #1927
This commit is contained in:
parent
cff31a3f6d
commit
b3780ebc16
@ -5,6 +5,8 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:ui' show Point, Offset;
|
import 'dart:ui' show Point, Offset;
|
||||||
|
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
import 'arena.dart';
|
import 'arena.dart';
|
||||||
import 'binding.dart';
|
import 'binding.dart';
|
||||||
import 'constants.dart';
|
import 'constants.dart';
|
||||||
@ -147,7 +149,9 @@ abstract class MultiDragPointerState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Releases any resources used by the object.
|
/// Releases any resources used by the object.
|
||||||
|
@mustCallSuper
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
_arenaEntry?.resolve(GestureDisposition.rejected);
|
||||||
assert(() { _pendingDelta = null; return true; });
|
assert(() { _pendingDelta = null; return true; });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -258,14 +262,14 @@ abstract class MultiDragGestureRecognizer<T extends MultiDragPointerState> exten
|
|||||||
assert(_pointers != null);
|
assert(_pointers != null);
|
||||||
assert(_pointers.containsKey(pointer));
|
assert(_pointers.containsKey(pointer));
|
||||||
GestureBinding.instance.pointerRouter.removeRoute(pointer, _handleEvent);
|
GestureBinding.instance.pointerRouter.removeRoute(pointer, _handleEvent);
|
||||||
_pointers[pointer].dispose();
|
_pointers.remove(pointer).dispose();
|
||||||
_pointers.remove(pointer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
for (int pointer in _pointers.keys)
|
for (int pointer in _pointers.keys.toList())
|
||||||
_removeState(pointer);
|
_removeState(pointer);
|
||||||
|
assert(_pointers.isEmpty);
|
||||||
_pointers = null;
|
_pointers = null;
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
@ -262,6 +262,12 @@ class _DraggableState<T> extends State<DraggableBase<T>> {
|
|||||||
_recognizer = config.createRecognizer(_startDrag);
|
_recognizer = config.createRecognizer(_startDrag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_recognizer.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
GestureRecognizer _recognizer;
|
GestureRecognizer _recognizer;
|
||||||
int _activeCount = 0;
|
int _activeCount = 0;
|
||||||
|
|
||||||
|
@ -871,6 +871,75 @@ void main() {
|
|||||||
await tester.pump();
|
await tester.pump();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Draggable disposes recognizer', (WidgetTester tester) async {
|
||||||
|
bool didTap = false;
|
||||||
|
await tester.pumpWidget(new Overlay(
|
||||||
|
initialEntries: <OverlayEntry>[
|
||||||
|
new OverlayEntry(
|
||||||
|
builder: (BuildContext context) => new GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
didTap = true;
|
||||||
|
},
|
||||||
|
child: new Draggable<dynamic>(
|
||||||
|
child: new Container(
|
||||||
|
decoration: new BoxDecoration(
|
||||||
|
backgroundColor: new Color(0xFFFFFF00)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
feedback: new Container(
|
||||||
|
width: 100.0,
|
||||||
|
height: 100.0,
|
||||||
|
decoration: new BoxDecoration(
|
||||||
|
backgroundColor: new Color(0xFFFF0000)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
));
|
||||||
|
|
||||||
|
await tester.startGesture(const Point(10.0, 10.0));
|
||||||
|
expect(didTap, isFalse);
|
||||||
|
|
||||||
|
// This tears down the draggable without terminating the gesture sequence,
|
||||||
|
// which used to trigger asserts in the multi-drag gesture recognizer.
|
||||||
|
await tester.pumpWidget(new Container(key: new UniqueKey()));
|
||||||
|
expect(didTap, isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Draggable plays nice with onTap', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(new Overlay(
|
||||||
|
initialEntries: <OverlayEntry>[
|
||||||
|
new OverlayEntry(
|
||||||
|
builder: (BuildContext context) => new GestureDetector(
|
||||||
|
onTap: () { /* registers a tap recognizer */ },
|
||||||
|
child: new Draggable<dynamic>(
|
||||||
|
child: new Container(
|
||||||
|
decoration: new BoxDecoration(
|
||||||
|
backgroundColor: new Color(0xFFFFFF00)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
feedback: new Container(
|
||||||
|
width: 100.0,
|
||||||
|
height: 100.0,
|
||||||
|
decoration: new BoxDecoration(
|
||||||
|
backgroundColor: new Color(0xFFFF0000)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
));
|
||||||
|
|
||||||
|
TestGesture firstGesture = await tester.startGesture(const Point(10.0, 10.0), pointer: 24);
|
||||||
|
TestGesture secondGesture = await tester.startGesture(const Point(10.0, 20.0), pointer: 25);
|
||||||
|
|
||||||
|
await firstGesture.moveBy(new Offset(100.0, 0.0));
|
||||||
|
await secondGesture.up();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class DragTargetData { }
|
class DragTargetData { }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user