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
01f4f1ac
Unverified
Commit
01f4f1ac
authored
Nov 13, 2019
by
Tong Mu
Committed by
GitHub
Nov 13, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ModalBarrier and Drawer barrier prevents mouse events (#44296)
* Add opaque to barriers * Detect opaque and test
parent
2d42b43a
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
227 additions
and
16 deletions
+227
-16
drawer.dart
packages/flutter/lib/src/material/drawer.dart
+6
-3
proxy_box.dart
packages/flutter/lib/src/rendering/proxy_box.dart
+12
-3
modal_barrier.dart
packages/flutter/lib/src/widgets/modal_barrier.dart
+8
-5
drawer_test.dart
packages/flutter/test/widgets/drawer_test.dart
+72
-2
modal_barrier_test.dart
packages/flutter/test/widgets/modal_barrier_test.dart
+75
-1
mouse_region_test.dart
packages/flutter/test/widgets/mouse_region_test.dart
+54
-2
No files found.
packages/flutter/lib/src/material/drawer.dart
View file @
01f4f1ac
...
...
@@ -546,9 +546,12 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
onTap:
close
,
child:
Semantics
(
label:
MaterialLocalizations
.
of
(
context
)?.
modalBarrierDismissLabel
,
child:
Container
(
// The drawer's "scrim"
color:
_scrimColorTween
.
evaluate
(
_controller
),
),
child:
MouseRegion
(
opaque:
true
,
child:
Container
(
// The drawer's "scrim"
color:
_scrimColorTween
.
evaluate
(
_controller
),
),
)
),
),
),
...
...
packages/flutter/lib/src/rendering/proxy_box.dart
View file @
01f4f1ac
...
...
@@ -2615,12 +2615,13 @@ class RenderMouseRegion extends RenderProxyBox {
PointerEnterEventListener
onEnter
,
PointerHoverEventListener
onHover
,
PointerExitEventListener
onExit
,
this
.
opaque
=
true
,
bool
opaque
=
true
,
RenderBox
child
,
})
:
assert
(
opaque
!=
null
),
_onEnter
=
onEnter
,
_onHover
=
onHover
,
_onExit
=
onExit
,
_opaque
=
opaque
,
_annotationIsActive
=
false
,
super
(
child
)
{
_hoverAnnotation
=
MouseTrackerAnnotation
(
...
...
@@ -2644,7 +2645,14 @@ class RenderMouseRegion extends RenderProxyBox {
/// pointer is within their areas.
///
/// This defaults to true.
bool
opaque
;
bool
get
opaque
=>
_opaque
;
bool
_opaque
;
set
opaque
(
bool
value
)
{
if
(
_opaque
!=
value
)
{
_opaque
=
value
;
_updateAnnotations
();
}
}
/// Called when a mouse pointer enters the region (with or without buttons
/// pressed).
...
...
@@ -2705,7 +2713,8 @@ class RenderMouseRegion extends RenderProxyBox {
final
bool
annotationWillBeActive
=
(
_onEnter
!=
null
||
_onHover
!=
null
||
_onExit
!=
null
_onExit
!=
null
||
opaque
)
&&
RendererBinding
.
instance
.
mouseTracker
.
mouseIsConnected
;
if
(
annotationWasActive
!=
annotationWillBeActive
)
{
...
...
packages/flutter/lib/src/widgets/modal_barrier.dart
View file @
01f4f1ac
...
...
@@ -101,11 +101,14 @@ class ModalBarrier extends StatelessWidget {
child:
Semantics
(
label:
semanticsDismissible
?
semanticsLabel
:
null
,
textDirection:
semanticsDismissible
&&
semanticsLabel
!=
null
?
Directionality
.
of
(
context
)
:
null
,
child:
ConstrainedBox
(
constraints:
const
BoxConstraints
.
expand
(),
child:
color
==
null
?
null
:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
color
,
child:
MouseRegion
(
opaque:
true
,
child:
ConstrainedBox
(
constraints:
const
BoxConstraints
.
expand
(),
child:
color
==
null
?
null
:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
color
,
),
),
),
),
...
...
packages/flutter/test/widgets/drawer_test.dart
View file @
01f4f1ac
...
...
@@ -78,6 +78,78 @@ void main() {
expect
(
find
.
text
(
'drawer'
),
findsNothing
);
});
testWidgets
(
'Drawer hover test'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
<
ScaffoldState
>
scaffoldKey
=
GlobalKey
<
ScaffoldState
>();
final
List
<
String
>
logs
=
<
String
>[];
final
TestGesture
gesture
=
await
tester
.
createGesture
(
kind:
PointerDeviceKind
.
mouse
);
addTearDown
(
gesture
.
removePointer
);
// Start out of hoverTarget
await
gesture
.
moveTo
(
const
Offset
(
100
,
100
));
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
key:
scaffoldKey
,
drawer:
const
Text
(
'drawer'
),
body:
Align
(
alignment:
Alignment
.
topLeft
,
child:
MouseRegion
(
onEnter:
(
_
)
{
logs
.
add
(
'enter'
);
},
onHover:
(
_
)
{
logs
.
add
(
'hover'
);
},
onExit:
(
_
)
{
logs
.
add
(
'exit'
);
},
child:
Container
(
width:
10
,
height:
10
),
),
),
),
),
);
expect
(
logs
,
isEmpty
);
expect
(
find
.
text
(
'drawer'
),
findsNothing
);
// When drawer is closed, hover is interactable
await
gesture
.
moveTo
(
const
Offset
(
5
,
5
));
await
tester
.
pump
();
// no effect
expect
(
logs
,
<
String
>[
'enter'
,
'hover'
]);
logs
.
clear
();
await
gesture
.
moveTo
(
const
Offset
(
20
,
20
));
await
tester
.
pump
();
// no effect
expect
(
logs
,
<
String
>[
'exit'
]);
logs
.
clear
();
// When drawer is open, hover is uninteractable
scaffoldKey
.
currentState
.
openDrawer
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
// animation done
expect
(
find
.
text
(
'drawer'
),
findsOneWidget
);
await
gesture
.
moveTo
(
const
Offset
(
5
,
5
));
await
tester
.
pump
();
// no effect
expect
(
logs
,
isEmpty
);
logs
.
clear
();
await
gesture
.
moveTo
(
const
Offset
(
20
,
20
));
await
tester
.
pump
();
// no effect
expect
(
logs
,
isEmpty
);
logs
.
clear
();
// Close drawer, hover is interactable again
await
tester
.
tapAt
(
const
Offset
(
750.0
,
100.0
));
// on the mask
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
// animation done
expect
(
find
.
text
(
'drawer'
),
findsNothing
);
await
gesture
.
moveTo
(
const
Offset
(
5
,
5
));
await
tester
.
pump
();
// no effect
expect
(
logs
,
<
String
>[
'enter'
,
'hover'
]);
logs
.
clear
();
await
gesture
.
moveTo
(
const
Offset
(
20
,
20
));
await
tester
.
pump
();
// no effect
expect
(
logs
,
<
String
>[
'exit'
]);
logs
.
clear
();
});
testWidgets
(
'Drawer drag cancel resume (LTR)'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
<
ScaffoldState
>
scaffoldKey
=
GlobalKey
<
ScaffoldState
>();
await
tester
.
pumpWidget
(
...
...
@@ -324,5 +396,3 @@ void main() {
semantics
.
dispose
();
});
}
packages/flutter/test/widgets/modal_barrier_test.dart
View file @
01f4f1ac
...
...
@@ -7,13 +7,15 @@ import 'package:flutter/foundation.dart';
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter/gestures.dart'
show
kSecondaryButton
;
import
'package:flutter/gestures.dart'
show
kSecondaryButton
,
PointerDeviceKind
;
import
'semantics_tester.dart'
;
void
main
(
)
{
bool
tapped
;
bool
hovered
;
Widget
tapTarget
;
Widget
hoverTarget
;
setUp
(()
{
tapped
=
false
;
...
...
@@ -27,6 +29,18 @@ void main() {
child:
Text
(
'target'
,
textDirection:
TextDirection
.
ltr
),
),
);
hovered
=
false
;
hoverTarget
=
MouseRegion
(
onHover:
(
_
)
{
hovered
=
true
;
},
onEnter:
(
_
)
{
hovered
=
true
;
},
onExit:
(
_
)
{
hovered
=
true
;
},
child:
const
SizedBox
(
width:
10.0
,
height:
10.0
,
child:
Text
(
'target'
,
textDirection:
TextDirection
.
ltr
),
),
);
});
testWidgets
(
'ModalBarrier prevents interactions with widgets behind it'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -45,6 +59,35 @@ void main() {
reason:
'because the tap is not prevented by ModalBarrier'
);
});
testWidgets
(
'ModalBarrier prevents hover interactions with widgets behind it'
,
(
WidgetTester
tester
)
async
{
final
Widget
subject
=
Stack
(
textDirection:
TextDirection
.
ltr
,
children:
<
Widget
>[
hoverTarget
,
const
ModalBarrier
(
dismissible:
false
),
],
);
final
TestGesture
gesture
=
await
tester
.
createGesture
(
kind:
PointerDeviceKind
.
mouse
);
addTearDown
(
gesture
.
removePointer
);
// Start out of hoverTarget
await
gesture
.
moveTo
(
const
Offset
(
100
,
100
));
await
tester
.
pumpWidget
(
subject
);
// Move into hoverTarget and tap
await
gesture
.
down
(
const
Offset
(
5
,
5
));
await
tester
.
pumpWidget
(
subject
);
await
gesture
.
up
();
await
tester
.
pumpWidget
(
subject
);
// Move out
await
gesture
.
moveTo
(
const
Offset
(
100
,
100
));
await
tester
.
pumpWidget
(
subject
);
expect
(
hovered
,
isFalse
,
reason:
'because the hover is not prevented by ModalBarrier'
);
});
testWidgets
(
'ModalBarrier does not prevent interactions with widgets in front of it'
,
(
WidgetTester
tester
)
async
{
final
Widget
subject
=
Stack
(
textDirection:
TextDirection
.
ltr
,
...
...
@@ -89,6 +132,37 @@ void main() {
reason:
'because the drag is prevented by ModalBarrier'
);
});
testWidgets
(
'ModalBarrier does not prevent hover interactions with widgets in front of it'
,
(
WidgetTester
tester
)
async
{
final
Widget
subject
=
Stack
(
textDirection:
TextDirection
.
ltr
,
children:
<
Widget
>[
const
ModalBarrier
(
dismissible:
false
),
hoverTarget
,
],
);
final
TestGesture
gesture
=
await
tester
.
createGesture
(
kind:
PointerDeviceKind
.
mouse
);
addTearDown
(
gesture
.
removePointer
);
// Start out of hoverTarget
await
gesture
.
moveTo
(
const
Offset
(
100
,
100
));
await
tester
.
pumpWidget
(
subject
);
expect
(
hovered
,
isFalse
);
// Move into hoverTarget
await
gesture
.
moveTo
(
const
Offset
(
5
,
5
));
await
tester
.
pumpWidget
(
subject
);
expect
(
hovered
,
isTrue
,
reason:
'because the hover is prevented by ModalBarrier'
);
hovered
=
false
;
// Move out
await
gesture
.
moveTo
(
const
Offset
(
100
,
100
));
await
tester
.
pumpWidget
(
subject
);
expect
(
hovered
,
isTrue
,
reason:
'because the hover is prevented by ModalBarrier'
);
hovered
=
false
;
});
testWidgets
(
'ModalBarrier pops the Navigator when dismissed by primay tap'
,
(
WidgetTester
tester
)
async
{
final
Map
<
String
,
WidgetBuilder
>
routes
=
<
String
,
WidgetBuilder
>{
'/'
:
(
BuildContext
context
)
=>
FirstWidget
(),
...
...
packages/flutter/test/widgets/mouse_region_test.dart
View file @
01f4f1ac
...
...
@@ -523,7 +523,7 @@ void main() {
await
tester
.
pumpWidget
(
Transform
.
scale
(
scale:
2.0
,
child:
const
MouseRegion
(),
child:
const
MouseRegion
(
opaque:
false
),
),
);
final
RenderMouseRegion
listener
=
tester
.
renderObject
(
find
.
byType
(
MouseRegion
));
...
...
@@ -534,10 +534,12 @@ void main() {
// transform.)
expect
(
tester
.
layers
.
whereType
<
TransformLayer
>(),
hasLength
(
1
));
// Test that needsCompositing updates correctly with callback change
await
tester
.
pumpWidget
(
Transform
.
scale
(
scale:
2.0
,
child:
MouseRegion
(
opaque:
false
,
onHover:
(
PointerHoverEvent
_
)
{},
),
),
...
...
@@ -550,13 +552,27 @@ void main() {
await
tester
.
pumpWidget
(
Transform
.
scale
(
scale:
2.0
,
child:
const
MouseRegion
(),
child:
const
MouseRegion
(
opaque:
false
),
),
);
expect
(
listener
.
needsCompositing
,
isFalse
);
// TransformLayer for `Transform.scale` is removed again as transform is
// executed directly on the canvas.
expect
(
tester
.
layers
.
whereType
<
TransformLayer
>(),
hasLength
(
1
));
// Test that needsCompositing updates correctly with `opaque` change
await
tester
.
pumpWidget
(
Transform
.
scale
(
scale:
2.0
,
child:
const
MouseRegion
(
opaque:
true
,
),
),
);
expect
(
listener
.
needsCompositing
,
isTrue
);
// Compositing is required, therefore a dedicated TransformLayer for
// `Transform.scale` is added.
expect
(
tester
.
layers
.
whereType
<
TransformLayer
>(),
hasLength
(
2
));
});
testWidgets
(
"Callbacks aren't called during build"
,
(
WidgetTester
tester
)
async
{
...
...
@@ -942,6 +958,42 @@ void main() {
});
});
testWidgets
(
'an empty opaque MouseRegion is effective'
,
(
WidgetTester
tester
)
async
{
bool
bottomRegionIsHovered
=
false
;
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
Stack
(
children:
<
Widget
>[
Align
(
alignment:
Alignment
.
topLeft
,
child:
MouseRegion
(
onEnter:
(
_
)
{
bottomRegionIsHovered
=
true
;
},
onHover:
(
_
)
{
bottomRegionIsHovered
=
true
;
},
onExit:
(
_
)
{
bottomRegionIsHovered
=
true
;
},
child:
Container
(
width:
10
,
height:
10
,
),
),
),
const
MouseRegion
(
opaque:
true
),
],
),
),
);
final
TestGesture
gesture
=
await
tester
.
createGesture
(
kind:
PointerDeviceKind
.
mouse
);
await
gesture
.
addPointer
(
location:
const
Offset
(
20
,
20
));
addTearDown
(
gesture
.
removePointer
);
await
gesture
.
moveTo
(
const
Offset
(
5
,
5
));
await
tester
.
pump
();
await
gesture
.
moveTo
(
const
Offset
(
20
,
20
));
await
tester
.
pump
();
expect
(
bottomRegionIsHovered
,
isFalse
);
});
testWidgets
(
'RenderMouseRegion
\'
s debugFillProperties when default'
,
(
WidgetTester
tester
)
async
{
final
DiagnosticPropertiesBuilder
builder
=
DiagnosticPropertiesBuilder
();
RenderMouseRegion
().
debugFillProperties
(
builder
);
...
...
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