Commit 3b76e7e2 authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Make tear-offs cacheable for RenderSemanticsGestureHandler (#11556)

* Make tear-offs cachable for RenderSemanticsGestureHandler

Fixes https://github.com/flutter/flutter/issues/11552

* comment fix

* refactor
parent 1d9f834f
...@@ -530,7 +530,7 @@ class RawGestureDetectorState extends State<RawGestureDetector> { ...@@ -530,7 +530,7 @@ class RawGestureDetectorState extends State<RawGestureDetector> {
final RenderSemanticsGestureHandler semanticsGestureHandler = context.findRenderObject(); final RenderSemanticsGestureHandler semanticsGestureHandler = context.findRenderObject();
context.visitChildElements((Element element) { context.visitChildElements((Element element) {
final _GestureSemantics widget = element.widget; final _GestureSemantics widget = element.widget;
widget._updateHandlers(semanticsGestureHandler, _recognizers); widget._updateHandlers(semanticsGestureHandler);
}); });
} }
} }
...@@ -600,45 +600,8 @@ class RawGestureDetectorState extends State<RawGestureDetector> { ...@@ -600,45 +600,8 @@ class RawGestureDetectorState extends State<RawGestureDetector> {
return widget.child == null ? HitTestBehavior.translucent : HitTestBehavior.deferToChild; return widget.child == null ? HitTestBehavior.translucent : HitTestBehavior.deferToChild;
} }
@override void _handleSemanticsTap() {
Widget build(BuildContext context) { final TapGestureRecognizer recognizer = _recognizers[TapGestureRecognizer];
Widget result = new Listener(
onPointerDown: _handlePointerDown,
behavior: widget.behavior ?? _defaultBehavior,
child: widget.child
);
if (!widget.excludeFromSemantics)
result = new _GestureSemantics(owner: this, child: result);
return result;
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder description) {
super.debugFillProperties(description);
if (_recognizers == null) {
description.add(new DiagnosticsNode.message('DISPOSED'));
} else {
final List<String> gestures = _recognizers.values.map<String>((GestureRecognizer recognizer) => recognizer.debugDescription).toList();
if (gestures.isEmpty)
gestures.add('<none>');
description.add(new IterableProperty<String>('gestures', gestures));
description.add(new IterableProperty<GestureRecognizer>('recognizers', _recognizers.values, hidden: true));
}
description.add(new EnumProperty<HitTestBehavior>('behavior', widget.behavior, defaultValue: null));
}
}
class _GestureSemantics extends SingleChildRenderObjectWidget {
const _GestureSemantics({
Key key,
Widget child,
this.owner
}) : super(key: key, child: child);
final RawGestureDetectorState owner;
void _handleTap() {
final TapGestureRecognizer recognizer = owner._recognizers[TapGestureRecognizer];
assert(recognizer != null); assert(recognizer != null);
if (recognizer.onTapDown != null) if (recognizer.onTapDown != null)
recognizer.onTapDown(new TapDownDetails()); recognizer.onTapDown(new TapDownDetails());
...@@ -648,16 +611,16 @@ class _GestureSemantics extends SingleChildRenderObjectWidget { ...@@ -648,16 +611,16 @@ class _GestureSemantics extends SingleChildRenderObjectWidget {
recognizer.onTap(); recognizer.onTap();
} }
void _handleLongPress() { void _handleSemanticsLongPress() {
final LongPressGestureRecognizer recognizer = owner._recognizers[LongPressGestureRecognizer]; final LongPressGestureRecognizer recognizer = _recognizers[LongPressGestureRecognizer];
assert(recognizer != null); assert(recognizer != null);
if (recognizer.onLongPress != null) if (recognizer.onLongPress != null)
recognizer.onLongPress(); recognizer.onLongPress();
} }
void _handleHorizontalDragUpdate(DragUpdateDetails updateDetails) { void _handleSemanticsHorizontalDragUpdate(DragUpdateDetails updateDetails) {
{ {
final HorizontalDragGestureRecognizer recognizer = owner._recognizers[HorizontalDragGestureRecognizer]; final HorizontalDragGestureRecognizer recognizer = _recognizers[HorizontalDragGestureRecognizer];
if (recognizer != null) { if (recognizer != null) {
if (recognizer.onDown != null) if (recognizer.onDown != null)
recognizer.onDown(new DragDownDetails()); recognizer.onDown(new DragDownDetails());
...@@ -671,7 +634,7 @@ class _GestureSemantics extends SingleChildRenderObjectWidget { ...@@ -671,7 +634,7 @@ class _GestureSemantics extends SingleChildRenderObjectWidget {
} }
} }
{ {
final PanGestureRecognizer recognizer = owner._recognizers[PanGestureRecognizer]; final PanGestureRecognizer recognizer = _recognizers[PanGestureRecognizer];
if (recognizer != null) { if (recognizer != null) {
if (recognizer.onDown != null) if (recognizer.onDown != null)
recognizer.onDown(new DragDownDetails()); recognizer.onDown(new DragDownDetails());
...@@ -686,9 +649,9 @@ class _GestureSemantics extends SingleChildRenderObjectWidget { ...@@ -686,9 +649,9 @@ class _GestureSemantics extends SingleChildRenderObjectWidget {
} }
} }
void _handleVerticalDragUpdate(DragUpdateDetails updateDetails) { void _handleSemanticsVerticalDragUpdate(DragUpdateDetails updateDetails) {
{ {
final VerticalDragGestureRecognizer recognizer = owner._recognizers[VerticalDragGestureRecognizer]; final VerticalDragGestureRecognizer recognizer = _recognizers[VerticalDragGestureRecognizer];
if (recognizer != null) { if (recognizer != null) {
if (recognizer.onDown != null) if (recognizer.onDown != null)
recognizer.onDown(new DragDownDetails()); recognizer.onDown(new DragDownDetails());
...@@ -702,7 +665,7 @@ class _GestureSemantics extends SingleChildRenderObjectWidget { ...@@ -702,7 +665,7 @@ class _GestureSemantics extends SingleChildRenderObjectWidget {
} }
} }
{ {
final PanGestureRecognizer recognizer = owner._recognizers[PanGestureRecognizer]; final PanGestureRecognizer recognizer = _recognizers[PanGestureRecognizer];
if (recognizer != null) { if (recognizer != null) {
if (recognizer.onDown != null) if (recognizer.onDown != null)
recognizer.onDown(new DragDownDetails()); recognizer.onDown(new DragDownDetails());
...@@ -718,20 +681,58 @@ class _GestureSemantics extends SingleChildRenderObjectWidget { ...@@ -718,20 +681,58 @@ class _GestureSemantics extends SingleChildRenderObjectWidget {
} }
@override @override
RenderSemanticsGestureHandler createRenderObject(BuildContext context) { Widget build(BuildContext context) {
final RenderSemanticsGestureHandler result = new RenderSemanticsGestureHandler(); Widget result = new Listener(
updateRenderObject(context, result); onPointerDown: _handlePointerDown,
behavior: widget.behavior ?? _defaultBehavior,
child: widget.child
);
if (!widget.excludeFromSemantics)
result = new _GestureSemantics(owner: this, child: result);
return result; return result;
} }
void _updateHandlers(RenderSemanticsGestureHandler renderObject, Map<Type, GestureRecognizer> recognizers) { @override
void debugFillProperties(DiagnosticPropertiesBuilder description) {
super.debugFillProperties(description);
if (_recognizers == null) {
description.add(new DiagnosticsNode.message('DISPOSED'));
} else {
final List<String> gestures = _recognizers.values.map<String>((GestureRecognizer recognizer) => recognizer.debugDescription).toList();
if (gestures.isEmpty)
gestures.add('<none>');
description.add(new IterableProperty<String>('gestures', gestures));
description.add(new IterableProperty<GestureRecognizer>('recognizers', _recognizers.values, hidden: true));
}
description.add(new EnumProperty<HitTestBehavior>('behavior', widget.behavior, defaultValue: null));
}
}
class _GestureSemantics extends SingleChildRenderObjectWidget {
const _GestureSemantics({
Key key,
Widget child,
this.owner
}) : super(key: key, child: child);
final RawGestureDetectorState owner;
@override
RenderSemanticsGestureHandler createRenderObject(BuildContext context) {
final RenderSemanticsGestureHandler renderObject = new RenderSemanticsGestureHandler();
_updateHandlers(renderObject);
return renderObject;
}
void _updateHandlers(RenderSemanticsGestureHandler renderObject) {
final Map<Type, GestureRecognizer> recognizers = owner._recognizers;
renderObject renderObject
..onTap = recognizers.containsKey(TapGestureRecognizer) ? _handleTap : null ..onTap = recognizers.containsKey(TapGestureRecognizer) ? owner._handleSemanticsTap : null
..onLongPress = recognizers.containsKey(LongPressGestureRecognizer) ? _handleLongPress : null ..onLongPress = recognizers.containsKey(LongPressGestureRecognizer) ? owner._handleSemanticsLongPress : null
..onHorizontalDragUpdate = recognizers.containsKey(HorizontalDragGestureRecognizer) || ..onHorizontalDragUpdate = recognizers.containsKey(HorizontalDragGestureRecognizer) ||
recognizers.containsKey(PanGestureRecognizer) ? _handleHorizontalDragUpdate : null recognizers.containsKey(PanGestureRecognizer) ? owner._handleSemanticsHorizontalDragUpdate : null
..onVerticalDragUpdate = recognizers.containsKey(VerticalDragGestureRecognizer) || ..onVerticalDragUpdate = recognizers.containsKey(VerticalDragGestureRecognizer) ||
recognizers.containsKey(PanGestureRecognizer) ? _handleVerticalDragUpdate : null; recognizers.containsKey(PanGestureRecognizer) ? owner._handleSemanticsVerticalDragUpdate : null;
} }
void _updateSemanticsActions(RenderSemanticsGestureHandler renderObject, Set<SemanticsAction> actions) { void _updateSemanticsActions(RenderSemanticsGestureHandler renderObject, Set<SemanticsAction> actions) {
...@@ -740,6 +741,6 @@ class _GestureSemantics extends SingleChildRenderObjectWidget { ...@@ -740,6 +741,6 @@ class _GestureSemantics extends SingleChildRenderObjectWidget {
@override @override
void updateRenderObject(BuildContext context, RenderSemanticsGestureHandler renderObject) { void updateRenderObject(BuildContext context, RenderSemanticsGestureHandler renderObject) {
_updateHandlers(renderObject, owner._recognizers); _updateHandlers(renderObject);
} }
} }
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
void main() { void main() {
...@@ -216,4 +217,35 @@ void main() { ...@@ -216,4 +217,35 @@ void main() {
await tester.tapAt(const Offset(10.0, 10.0)); await tester.tapAt(const Offset(10.0, 10.0));
expect(didTap, isFalse); expect(didTap, isFalse);
}); });
testWidgets('cache unchanged callbacks', (WidgetTester tester) async {
final GestureTapCallback inputCallback = () {};
await tester.pumpWidget(
new Center(
child: new GestureDetector(
onTap: inputCallback,
child: new Container(),
)
)
);
final RenderSemanticsGestureHandler renderObj1 = tester.renderObject(find.byType(GestureDetector));
final GestureTapCallback actualCallback1 = renderObj1.onTap;
await tester.pumpWidget(
new Center(
child: new GestureDetector(
onTap: inputCallback,
child: new Container(),
)
)
);
final RenderSemanticsGestureHandler renderObj2 = tester.renderObject(find.byType(GestureDetector));
final GestureTapCallback actualCallback2 = renderObj2.onTap;
expect(renderObj1, same(renderObj2));
expect(actualCallback1, same(actualCallback2)); // Should be cached.
});
} }
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