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
71d96ddf
Unverified
Commit
71d96ddf
authored
1 year ago
by
Qun Cheng
Committed by
GitHub
1 year ago
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add Expanded/Collapsed State for Semantics (#131233)
parent
e0b6b6c4
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
201 additions
and
17 deletions
+201
-17
menu_anchor.dart
packages/flutter/lib/src/material/menu_anchor.dart
+18
-14
custom_paint.dart
packages/flutter/lib/src/rendering/custom_paint.dart
+3
-0
proxy_box.dart
packages/flutter/lib/src/rendering/proxy_box.dart
+3
-0
semantics.dart
packages/flutter/lib/src/semantics/semantics.dart
+24
-0
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+2
-0
menu_anchor_test.dart
packages/flutter/test/material/menu_anchor_test.dart
+127
-1
custom_painter_test.dart
packages/flutter/test/widgets/custom_painter_test.dart
+3
-1
semantics_test.dart
packages/flutter/test/widgets/semantics_test.dart
+3
-1
matchers.dart
packages/flutter_test/lib/src/matchers.dart
+12
-0
matchers_test.dart
packages/flutter_test/test/matchers_test.dart
+6
-0
No files found.
packages/flutter/lib/src/material/menu_anchor.dart
View file @
71d96ddf
...
...
@@ -1079,7 +1079,7 @@ class _MenuItemButtonState extends State<MenuItemButton> {
);
}
return
child
;
return
MergeSemantics
(
child:
child
)
;
}
void
_handleFocusChange
()
{
...
...
@@ -1904,19 +1904,23 @@ class _SubmenuButtonState extends State<SubmenuButton> {
controller
.
_anchor
!.
_focusButton
();
}
}
child
=
TextButton
(
style:
mergedStyle
,
focusNode:
_buttonFocusNode
,
onHover:
_enabled
?
(
bool
hovering
)
=>
handleHover
(
hovering
,
context
)
:
null
,
onPressed:
_enabled
?
()
=>
toggleShowMenu
(
context
)
:
null
,
isSemanticButton:
null
,
child:
_MenuItemLabel
(
leadingIcon:
widget
.
leadingIcon
,
trailingIcon:
widget
.
trailingIcon
,
hasSubmenu:
true
,
showDecoration:
(
controller
.
_anchor
!.
_parent
?.
_orientation
??
Axis
.
horizontal
)
==
Axis
.
vertical
,
child:
child
??
const
SizedBox
(),
child
=
MergeSemantics
(
child:
Semantics
(
expanded:
controller
.
isOpen
,
child:
TextButton
(
style:
mergedStyle
,
focusNode:
_buttonFocusNode
,
onHover:
_enabled
?
(
bool
hovering
)
=>
handleHover
(
hovering
,
context
)
:
null
,
onPressed:
_enabled
?
()
=>
toggleShowMenu
(
context
)
:
null
,
isSemanticButton:
null
,
child:
_MenuItemLabel
(
leadingIcon:
widget
.
leadingIcon
,
trailingIcon:
widget
.
trailingIcon
,
hasSubmenu:
true
,
showDecoration:
(
controller
.
_anchor
!.
_parent
?.
_orientation
??
Axis
.
horizontal
)
==
Axis
.
vertical
,
child:
child
??
const
SizedBox
(),
),
),
),
);
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/rendering/custom_paint.dart
View file @
71d96ddf
...
...
@@ -900,6 +900,9 @@ class RenderCustomPaint extends RenderProxyBox {
if
(
properties
.
button
!=
null
)
{
config
.
isButton
=
properties
.
button
!;
}
if
(
properties
.
expanded
!=
null
)
{
config
.
isExpanded
=
properties
.
expanded
;
}
if
(
properties
.
link
!=
null
)
{
config
.
isLink
=
properties
.
link
!;
}
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/rendering/proxy_box.dart
View file @
71d96ddf
...
...
@@ -4319,6 +4319,9 @@ class RenderSemanticsAnnotations extends RenderProxyBox {
if
(
_properties
.
button
!=
null
)
{
config
.
isButton
=
_properties
.
button
!;
}
if
(
_properties
.
expanded
!=
null
)
{
config
.
isExpanded
=
_properties
.
expanded
;
}
if
(
_properties
.
link
!=
null
)
{
config
.
isLink
=
_properties
.
link
!;
}
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/semantics/semantics.dart
View file @
71d96ddf
...
...
@@ -870,6 +870,7 @@ class SemanticsProperties extends DiagnosticableTree {
this
.
enabled
,
this
.
checked
,
this
.
mixed
,
this
.
expanded
,
this
.
selected
,
this
.
toggled
,
this
.
button
,
...
...
@@ -964,6 +965,14 @@ class SemanticsProperties extends DiagnosticableTree {
/// This is mutually exclusive with [checked] and [toggled].
final
bool
?
mixed
;
/// If non-null, indicates that this subtree represents something
/// that can be in an "expanded" or "collapsed" state.
///
/// For example, if a [SubmenuButton] is opened, this property
/// should be set to true; otherwise, this property should be
/// false.
final
bool
?
expanded
;
/// If non-null, indicates that this subtree represents a toggle switch
/// or similar widget with an "on" state, and what its current
/// state is.
...
...
@@ -1612,6 +1621,7 @@ class SemanticsProperties extends DiagnosticableTree {
super
.
debugFillProperties
(
properties
);
properties
.
add
(
DiagnosticsProperty
<
bool
>(
'checked'
,
checked
,
defaultValue:
null
));
properties
.
add
(
DiagnosticsProperty
<
bool
>(
'mixed'
,
mixed
,
defaultValue:
null
));
properties
.
add
(
DiagnosticsProperty
<
bool
>(
'expanded'
,
expanded
,
defaultValue:
null
));
properties
.
add
(
DiagnosticsProperty
<
bool
>(
'selected'
,
selected
,
defaultValue:
null
));
properties
.
add
(
StringProperty
(
'label'
,
label
,
defaultValue:
null
));
properties
.
add
(
AttributedStringProperty
(
'attributedLabel'
,
attributedLabel
,
defaultValue:
null
));
...
...
@@ -4398,6 +4408,20 @@ class SemanticsConfiguration {
_setFlag
(
SemanticsFlag
.
isSelected
,
value
);
}
/// If this node has Boolean state that can be controlled by the user, whether
/// that state is expanded or collapsed, corresponding to true and false, respectively.
///
/// Do not call the setter for this field if the owning [RenderObject] doesn't
/// have expanded/collapsed state that can be controlled by the user.
///
/// The getter returns null if the owning [RenderObject] does not have
/// expanded/collapsed state.
bool
?
get
isExpanded
=>
_hasFlag
(
SemanticsFlag
.
hasExpandedState
)
?
_hasFlag
(
SemanticsFlag
.
isExpanded
)
:
null
;
set
isExpanded
(
bool
?
value
)
{
_setFlag
(
SemanticsFlag
.
hasExpandedState
,
true
);
_setFlag
(
SemanticsFlag
.
isExpanded
,
value
!);
}
/// Whether the owning [RenderObject] is currently enabled.
///
/// A disabled object does not respond to user interactions. Only objects that
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/basic.dart
View file @
71d96ddf
...
...
@@ -7138,6 +7138,7 @@ class Semantics extends SingleChildRenderObjectWidget {
bool
?
hidden
,
bool
?
image
,
bool
?
liveRegion
,
bool
?
expanded
,
int
?
maxValueLength
,
int
?
currentValueLength
,
String
?
label
,
...
...
@@ -7186,6 +7187,7 @@ class Semantics extends SingleChildRenderObjectWidget {
enabled:
enabled
,
checked:
checked
,
mixed:
mixed
,
expanded:
expanded
,
toggled:
toggled
,
selected:
selected
,
button:
button
,
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/test/material/menu_anchor_test.dart
View file @
71d96ddf
...
...
@@ -3181,7 +3181,8 @@ void main() {
children:
<
TestSemantics
>[
TestSemantics
(
rect:
const
Rect
.
fromLTRB
(
0.0
,
0.0
,
88.0
,
48.0
),
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
hasEnabledState
],
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
hasEnabledState
,
SemanticsFlag
.
hasExpandedState
],
label:
'ABC'
,
textDirection:
TextDirection
.
ltr
,
),
...
...
@@ -3194,6 +3195,131 @@ void main() {
semantics
.
dispose
();
});
testWidgets
(
'SubmenuButton expanded/collapsed state'
,
(
WidgetTester
tester
)
async
{
final
SemanticsTester
semantics
=
SemanticsTester
(
tester
);
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Center
(
child:
SubmenuButton
(
onHover:
(
bool
value
)
{},
style:
SubmenuButton
.
styleFrom
(
fixedSize:
const
Size
(
88.0
,
36.0
)),
menuChildren:
<
Widget
>[
MenuItemButton
(
child:
const
Text
(
'Item 0'
),
onPressed:
()
{},
),
],
child:
const
Text
(
'ABC'
),
),
),
),
);
// Test expanded state.
await
tester
.
tap
(
find
.
text
(
'ABC'
));
await
tester
.
pumpAndSettle
();
expect
(
semantics
,
hasSemantics
(
TestSemantics
.
root
(
children:
<
TestSemantics
>[
TestSemantics
(
id:
1
,
rect:
const
Rect
.
fromLTRB
(
0.0
,
0.0
,
800.0
,
600.0
),
children:
<
TestSemantics
>
[
TestSemantics
(
id:
2
,
rect:
const
Rect
.
fromLTRB
(
0.0
,
0.0
,
800.0
,
600.0
),
children:
<
TestSemantics
>
[
TestSemantics
(
id:
3
,
rect:
const
Rect
.
fromLTRB
(
0.0
,
0.0
,
800.0
,
600.0
),
flags:
<
SemanticsFlag
>
[
SemanticsFlag
.
scopesRoute
],
children:
<
TestSemantics
>
[
TestSemantics
(
id:
4
,
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
hasExpandedState
,
SemanticsFlag
.
isExpanded
,
SemanticsFlag
.
isFocused
,
SemanticsFlag
.
hasEnabledState
,
SemanticsFlag
.
isEnabled
,
SemanticsFlag
.
isFocusable
],
actions:
<
SemanticsAction
>[
SemanticsAction
.
tap
],
label:
'ABC'
,
rect:
const
Rect
.
fromLTRB
(
0.0
,
0.0
,
88.0
,
48.0
),
)
]
)
]
),
TestSemantics
(
id:
6
,
rect:
const
Rect
.
fromLTRB
(
0.0
,
0.0
,
123.0
,
64.0
),
children:
<
TestSemantics
>
[
TestSemantics
(
id:
7
,
rect:
const
Rect
.
fromLTRB
(
0.0
,
0.0
,
123.0
,
48.0
),
flags:
<
SemanticsFlag
>
[
SemanticsFlag
.
hasImplicitScrolling
],
children:
<
TestSemantics
>
[
TestSemantics
(
id:
8
,
label:
'Item 0'
,
rect:
const
Rect
.
fromLTRB
(
0.0
,
0.0
,
123.0
,
48.0
),
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
hasEnabledState
,
SemanticsFlag
.
isEnabled
,
SemanticsFlag
.
isFocusable
],
actions:
<
SemanticsAction
>[
SemanticsAction
.
tap
],
),
],
),
],
),
],
),
],
),
ignoreTransform:
true
,
),
);
// Test collapsed state.
await
tester
.
tap
(
find
.
text
(
'ABC'
));
await
tester
.
pumpAndSettle
();
expect
(
semantics
,
hasSemantics
(
TestSemantics
.
root
(
children:
<
TestSemantics
>[
TestSemantics
(
id:
1
,
rect:
const
Rect
.
fromLTRB
(
0.0
,
0.0
,
800.0
,
600.0
),
children:
<
TestSemantics
>
[
TestSemantics
(
id:
2
,
rect:
const
Rect
.
fromLTRB
(
0.0
,
0.0
,
800.0
,
600.0
),
children:
<
TestSemantics
>
[
TestSemantics
(
id:
3
,
rect:
const
Rect
.
fromLTRB
(
0.0
,
0.0
,
800.0
,
600.0
),
flags:
<
SemanticsFlag
>
[
SemanticsFlag
.
scopesRoute
],
children:
<
TestSemantics
>
[
TestSemantics
(
id:
4
,
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
hasExpandedState
,
SemanticsFlag
.
isFocused
,
SemanticsFlag
.
hasEnabledState
,
SemanticsFlag
.
isEnabled
,
SemanticsFlag
.
isFocusable
],
actions:
<
SemanticsAction
>[
SemanticsAction
.
tap
],
label:
'ABC'
,
rect:
const
Rect
.
fromLTRB
(
0.0
,
0.0
,
88.0
,
48.0
),
)
]
)
]
),
],
),
],
),
ignoreTransform:
true
,
),
);
semantics
.
dispose
();
});
});
}
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/test/widgets/custom_painter_test.dart
View file @
71d96ddf
...
...
@@ -440,6 +440,7 @@ void _defineTests() {
image:
true
,
liveRegion:
true
,
toggled:
true
,
expanded:
true
,
),
),
),
...
...
@@ -494,6 +495,7 @@ void _defineTests() {
namesRoute:
true
,
image:
true
,
liveRegion:
true
,
expanded:
true
,
),
),
),
...
...
@@ -520,7 +522,7 @@ void _defineTests() {
);
expect
(
semantics
,
hasSemantics
(
expectedSemantics
,
ignoreRect:
true
,
ignoreTransform:
true
));
semantics
.
dispose
();
}
,
skip:
true
);
// https://github.com/flutter/flutter/issues/127617
}
);
group
(
'diffing'
,
()
{
testWidgets
(
'complains about duplicate keys'
,
(
WidgetTester
tester
)
async
{
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/test/widgets/semantics_test.dart
View file @
71d96ddf
...
...
@@ -609,6 +609,7 @@ void main() {
namesRoute:
true
,
image:
true
,
liveRegion:
true
,
expanded:
true
,
),
);
final
List
<
SemanticsFlag
>
flags
=
SemanticsFlag
.
values
.
toList
();
...
...
@@ -691,6 +692,7 @@ void main() {
namesRoute:
true
,
image:
true
,
liveRegion:
true
,
expanded:
true
,
),
);
flags
...
...
@@ -706,7 +708,7 @@ void main() {
],
);
expect
(
semantics
,
hasSemantics
(
expectedSemantics
,
ignoreId:
true
));
}
,
skip:
true
);
// https://github.com/flutter/flutter/issues/127617
}
);
testWidgets
(
'Actions can be replaced without triggering semantics update'
,
(
WidgetTester
tester
)
async
{
final
SemanticsTester
semantics
=
SemanticsTester
(
tester
);
...
...
This diff is collapsed.
Click to expand it.
packages/flutter_test/lib/src/matchers.dart
View file @
71d96ddf
...
...
@@ -564,6 +564,8 @@ Matcher matchesSemantics({
bool
hasToggledState
=
false
,
bool
isToggled
=
false
,
bool
hasImplicitScrolling
=
false
,
bool
hasExpandedState
=
false
,
bool
isExpanded
=
false
,
// Actions //
bool
hasTapAction
=
false
,
bool
hasLongPressAction
=
false
,
...
...
@@ -640,6 +642,8 @@ Matcher matchesSemantics({
hasToggledState:
hasToggledState
,
isToggled:
isToggled
,
hasImplicitScrolling:
hasImplicitScrolling
,
hasExpandedState:
hasExpandedState
,
isExpanded:
isExpanded
,
// Actions
hasTapAction:
hasTapAction
,
hasLongPressAction:
hasLongPressAction
,
...
...
@@ -737,6 +741,8 @@ Matcher containsSemantics({
bool
?
hasToggledState
,
bool
?
isToggled
,
bool
?
hasImplicitScrolling
,
bool
?
hasExpandedState
,
bool
?
isExpanded
,
// Actions
bool
?
hasTapAction
,
bool
?
hasLongPressAction
,
...
...
@@ -813,6 +819,8 @@ Matcher containsSemantics({
hasToggledState:
hasToggledState
,
isToggled:
isToggled
,
hasImplicitScrolling:
hasImplicitScrolling
,
hasExpandedState:
hasExpandedState
,
isExpanded:
isExpanded
,
// Actions
hasTapAction:
hasTapAction
,
hasLongPressAction:
hasLongPressAction
,
...
...
@@ -2111,6 +2119,8 @@ class _MatchesSemanticsData extends Matcher {
required
bool
?
hasToggledState
,
required
bool
?
isToggled
,
required
bool
?
hasImplicitScrolling
,
required
bool
?
hasExpandedState
,
required
bool
?
isExpanded
,
// Actions
required
bool
?
hasTapAction
,
required
bool
?
hasLongPressAction
,
...
...
@@ -2166,6 +2176,8 @@ class _MatchesSemanticsData extends Matcher {
if
(
isToggled
!=
null
)
SemanticsFlag
.
isToggled
:
isToggled
,
if
(
hasImplicitScrolling
!=
null
)
SemanticsFlag
.
hasImplicitScrolling
:
hasImplicitScrolling
,
if
(
isSlider
!=
null
)
SemanticsFlag
.
isSlider
:
isSlider
,
if
(
hasExpandedState
!=
null
)
SemanticsFlag
.
hasExpandedState
:
hasExpandedState
,
if
(
isExpanded
!=
null
)
SemanticsFlag
.
isExpanded
:
isExpanded
,
},
actions
=
<
SemanticsAction
,
bool
>{
if
(
hasTapAction
!=
null
)
SemanticsAction
.
tap
:
hasTapAction
,
...
...
This diff is collapsed.
Click to expand it.
packages/flutter_test/test/matchers_test.dart
View file @
71d96ddf
...
...
@@ -683,6 +683,8 @@ void main() {
hasToggledState:
true
,
isToggled:
true
,
hasImplicitScrolling:
true
,
hasExpandedState:
true
,
isExpanded:
true
,
/* Actions */
hasTapAction:
true
,
hasLongPressAction:
true
,
...
...
@@ -966,6 +968,8 @@ void main() {
hasToggledState:
true
,
isToggled:
true
,
hasImplicitScrolling:
true
,
hasExpandedState:
true
,
isExpanded:
true
,
/* Actions */
hasTapAction:
true
,
hasLongPressAction:
true
,
...
...
@@ -1055,6 +1059,8 @@ void main() {
hasToggledState:
false
,
isToggled:
false
,
hasImplicitScrolling:
false
,
hasExpandedState:
false
,
isExpanded:
false
,
/* Actions */
hasTapAction:
false
,
hasLongPressAction:
false
,
...
...
This diff is collapsed.
Click to expand it.
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