Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
6d67fbb9
Unverified
Commit
6d67fbb9
authored
Oct 18, 2022
by
Greg Spencer
Committed by
GitHub
Oct 18, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add HitTestBehavior to TapRegion (#113634)
parent
94d3a802
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
131 additions
and
12 deletions
+131
-12
proxy_box.dart
packages/flutter/lib/src/rendering/proxy_box.dart
+6
-1
gesture_detector.dart
packages/flutter/lib/src/widgets/gesture_detector.dart
+5
-1
tap_region.dart
packages/flutter/lib/src/widgets/tap_region.dart
+30
-10
tap_region_test.dart
packages/flutter/test/widgets/tap_region_test.dart
+90
-0
No files found.
packages/flutter/lib/src/rendering/proxy_box.dart
View file @
6d67fbb9
...
...
@@ -173,7 +173,12 @@ abstract class RenderProxyBoxWithHitTestBehavior extends RenderProxyBox {
RenderBox
?
child
,
})
:
super
(
child
);
/// How to behave during hit testing.
/// How to behave during hit testing when deciding how the hit test propagates
/// to children and whether to consider targets behind this one.
///
/// Defaults to [HitTestBehavior.deferToChild].
///
/// See [HitTestBehavior] for the allowed values and their meanings.
HitTestBehavior
behavior
;
@override
...
...
packages/flutter/lib/src/widgets/gesture_detector.dart
View file @
6d67fbb9
...
...
@@ -970,10 +970,14 @@ class GestureDetector extends StatelessWidget {
/// detecting screens.
final
GestureForcePressEndCallback
?
onForcePressEnd
;
/// How this gesture detector should behave during hit testing.
/// How this gesture detector should behave during hit testing when deciding
/// how the hit test propagates to children and whether to consider targets
/// behind this one.
///
/// This defaults to [HitTestBehavior.deferToChild] if [child] is not null and
/// [HitTestBehavior.translucent] if child is null.
///
/// See [HitTestBehavior] for the allowed values and their meanings.
final
HitTestBehavior
?
behavior
;
/// Whether to exclude these gestures from the semantics tree. For
...
...
packages/flutter/lib/src/widgets/tap_region.dart
View file @
6d67fbb9
...
...
@@ -312,6 +312,7 @@ class TapRegion extends SingleChildRenderObjectWidget {
super
.
key
,
required
super
.
child
,
this
.
enabled
=
true
,
this
.
behavior
=
HitTestBehavior
.
deferToChild
,
this
.
onTapOutside
,
this
.
onTapInside
,
this
.
groupId
,
...
...
@@ -321,6 +322,14 @@ class TapRegion extends SingleChildRenderObjectWidget {
/// Whether or not this [TapRegion] is enabled as part of the composite region.
final
bool
enabled
;
/// How to behave during hit testing when deciding how the hit test propagates
/// to children and whether to consider targets behind this [TapRegion].
///
/// Defaults to [HitTestBehavior.deferToChild].
///
/// See [HitTestBehavior] for the allowed values and their meanings.
final
HitTestBehavior
behavior
;
/// A callback to be invoked when a tap is detected outside of this
/// [TapRegion] and any other region with the same [groupId], if any.
///
...
...
@@ -358,6 +367,7 @@ class TapRegion extends SingleChildRenderObjectWidget {
return
RenderTapRegion
(
registry:
TapRegionRegistry
.
maybeOf
(
context
),
enabled:
enabled
,
behavior:
behavior
,
onTapOutside:
onTapOutside
,
onTapInside:
onTapInside
,
groupId:
groupId
,
...
...
@@ -367,12 +377,14 @@ class TapRegion extends SingleChildRenderObjectWidget {
@override
void
updateRenderObject
(
BuildContext
context
,
covariant
RenderTapRegion
renderObject
)
{
renderObject
.
registry
=
TapRegionRegistry
.
maybeOf
(
context
);
renderObject
.
enabled
=
enabled
;
renderObject
.
groupId
=
groupId
;
renderObject
.
onTapOutside
=
onTapOutside
;
renderObject
.
onTapInside
=
onTapInside
;
if
(
kReleaseMode
)
{
renderObject
..
registry
=
TapRegionRegistry
.
maybeOf
(
context
)
..
enabled
=
enabled
..
behavior
=
behavior
..
groupId
=
groupId
..
onTapOutside
=
onTapOutside
..
onTapInside
=
onTapInside
;
if
(!
kReleaseMode
)
{
renderObject
.
debugLabel
=
debugLabel
;
}
}
...
...
@@ -380,9 +392,10 @@ class TapRegion extends SingleChildRenderObjectWidget {
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
properties
.
add
(
FlagProperty
(
'enabled'
,
value:
enabled
,
ifFalse:
'DISABLED'
,
defaultValue:
true
));
properties
.
add
(
DiagnosticsProperty
<
HitTestBehavior
>(
'behavior'
,
behavior
,
defaultValue:
HitTestBehavior
.
deferToChild
));
properties
.
add
(
DiagnosticsProperty
<
Object
?>(
'debugLabel'
,
debugLabel
,
defaultValue:
null
));
properties
.
add
(
DiagnosticsProperty
<
Object
?>(
'groupId'
,
groupId
,
defaultValue:
null
));
properties
.
add
(
FlagProperty
(
'enabled'
,
value:
enabled
,
ifFalse:
'DISABLED'
,
defaultValue:
true
));
}
}
...
...
@@ -393,8 +406,9 @@ class TapRegion extends SingleChildRenderObjectWidget {
/// system.
///
/// This render object indicates to the nearest ancestor [TapRegionSurface] that
/// the region occupied by its child will participate in the tap detection for
/// that surface.
/// the region occupied by its child (or itself if [behavior] is
/// [HitTestBehavior.opaque]) will participate in the tap detection for that
/// surface.
///
/// If this region belongs to a group (by virtue of its [groupId]), all the
/// regions in the group will act as one.
...
...
@@ -402,17 +416,23 @@ class TapRegion extends SingleChildRenderObjectWidget {
/// If there is no [RenderTapRegionSurface] ancestor in the render tree,
/// [RenderTapRegion] will do nothing.
///
/// The [behavior] attribute describes how to behave during hit testing when
/// deciding how the hit test propagates to children and whether to consider
/// targets behind the tap region. Defaults to [HitTestBehavior.deferToChild].
/// See [HitTestBehavior] for the allowed values and their meanings.
///
/// See also:
///
/// * [TapRegion], a widget that inserts a [RenderTapRegion] into the render
/// tree.
class
RenderTapRegion
extends
RenderProxyBox
{
class
RenderTapRegion
extends
RenderProxyBox
WithHitTestBehavior
{
/// Creates a [RenderTapRegion].
RenderTapRegion
({
TapRegionRegistry
?
registry
,
bool
enabled
=
true
,
this
.
onTapOutside
,
this
.
onTapInside
,
super
.
behavior
=
HitTestBehavior
.
deferToChild
,
Object
?
groupId
,
String
?
debugLabel
,
})
:
_registry
=
registry
,
...
...
packages/flutter/test/widgets/tap_region_test.dart
View file @
6d67fbb9
...
...
@@ -4,6 +4,7 @@
import
'dart:ui'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
...
...
@@ -99,6 +100,7 @@ void main() {
await
click
(
find
.
text
(
'Outside Surface'
));
expect
(
tappedOutside
,
isEmpty
);
});
testWidgets
(
'TapRegionSurface detects inside taps'
,
(
WidgetTester
tester
)
async
{
final
Set
<
String
>
tappedInside
=
<
String
>{};
await
tester
.
pumpWidget
(
...
...
@@ -185,6 +187,94 @@ void main() {
await
click
(
find
.
text
(
'Outside Surface'
));
expect
(
tappedInside
,
isEmpty
);
});
testWidgets
(
'TapRegionSurface detects inside taps correctly with behavior'
,
(
WidgetTester
tester
)
async
{
final
Set
<
String
>
tappedInside
=
<
String
>{};
const
ValueKey
<
String
>
noGroupKey
=
ValueKey
<
String
>(
'No Group'
);
const
ValueKey
<
String
>
group1AKey
=
ValueKey
<
String
>(
'Group 1 A'
);
const
ValueKey
<
String
>
group1BKey
=
ValueKey
<
String
>(
'Group 1 B'
);
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
Column
(
children:
<
Widget
>[
const
Text
(
'Outside Surface'
),
TapRegionSurface
(
child:
Row
(
children:
<
Widget
>[
ConstrainedBox
(
constraints:
const
BoxConstraints
.
tightFor
(
width:
100
,
height:
100
),
child:
TapRegion
(
// ignore: avoid_redundant_argument_values
behavior:
HitTestBehavior
.
deferToChild
,
onTapInside:
(
PointerEvent
event
)
{
tappedInside
.
add
(
noGroupKey
.
value
);
},
child:
Stack
(
key:
noGroupKey
),
),
),
ConstrainedBox
(
constraints:
const
BoxConstraints
.
tightFor
(
width:
100
,
height:
100
),
child:
TapRegion
(
groupId:
1
,
behavior:
HitTestBehavior
.
opaque
,
onTapInside:
(
PointerEvent
event
)
{
tappedInside
.
add
(
group1AKey
.
value
);
},
child:
Stack
(
key:
group1AKey
),
),
),
ConstrainedBox
(
constraints:
const
BoxConstraints
.
tightFor
(
width:
100
,
height:
100
),
child:
TapRegion
(
groupId:
1
,
behavior:
HitTestBehavior
.
translucent
,
onTapInside:
(
PointerEvent
event
)
{
tappedInside
.
add
(
group1BKey
.
value
);
},
child:
Stack
(
key:
group1BKey
),
),
),
],
),
),
],
),
),
);
await
tester
.
pump
();
Future
<
void
>
click
(
Finder
finder
)
async
{
final
TestGesture
gesture
=
await
tester
.
startGesture
(
tester
.
getCenter
(
finder
),
kind:
PointerDeviceKind
.
mouse
,
);
await
gesture
.
up
();
await
gesture
.
removePointer
();
}
expect
(
tappedInside
,
isEmpty
);
await
click
(
find
.
byKey
(
noGroupKey
));
expect
(
tappedInside
,
isEmpty
);
// No hittable children, so no hit.
await
click
(
find
.
byKey
(
group1AKey
));
// No hittable children, but set to opaque, so it hits, triggering the
// group.
expect
(
tappedInside
,
equals
(<
String
>{
'Group 1 A'
,
'Group 1 B'
,
}),
);
tappedInside
.
clear
();
await
click
(
find
.
byKey
(
group1BKey
));
expect
(
tappedInside
,
isEmpty
);
// No hittable children while translucent, so no hit.
tappedInside
.
clear
();
});
testWidgets
(
'Setting the group updates the registration'
,
(
WidgetTester
tester
)
async
{
final
Set
<
String
>
tappedOutside
=
<
String
>{};
await
tester
.
pumpWidget
(
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment