mirror of
https://github.com/flutter/flutter
synced 2024-09-13 05:11:45 +00:00
Fix dropdown button semantics (#19932)
This commit is contained in:
parent
a7595e535c
commit
ee396272d3
|
@ -139,6 +139,7 @@ class _DropdownMenuState<T> extends State<_DropdownMenu<T>> {
|
|||
//
|
||||
// When the menu is dismissed we just fade the entire thing out
|
||||
// in the first 0.25s.
|
||||
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
||||
final _DropdownRoute<T> route = widget.route;
|
||||
final double unit = 0.5 / (route.items.length + 1.5);
|
||||
final List<Widget> children = <Widget>[];
|
||||
|
@ -175,24 +176,30 @@ class _DropdownMenuState<T> extends State<_DropdownMenu<T>> {
|
|||
selectedIndex: route.selectedIndex,
|
||||
resize: _resize,
|
||||
),
|
||||
child: new Material(
|
||||
type: MaterialType.transparency,
|
||||
textStyle: route.style,
|
||||
child: new ScrollConfiguration(
|
||||
behavior: const _DropdownScrollBehavior(),
|
||||
child: new Scrollbar(
|
||||
child: new ListView(
|
||||
controller: widget.route.scrollController,
|
||||
padding: kMaterialListPadding,
|
||||
itemExtent: _kMenuItemHeight,
|
||||
shrinkWrap: true,
|
||||
children: children,
|
||||
child: new Semantics(
|
||||
scopesRoute: true,
|
||||
namesRoute: true,
|
||||
explicitChildNodes: true,
|
||||
label: localizations.popupMenuLabel,
|
||||
child: new Material(
|
||||
type: MaterialType.transparency,
|
||||
textStyle: route.style,
|
||||
child: new ScrollConfiguration(
|
||||
behavior: const _DropdownScrollBehavior(),
|
||||
child: new Scrollbar(
|
||||
child: new ListView(
|
||||
controller: widget.route.scrollController,
|
||||
padding: kMaterialListPadding,
|
||||
itemExtent: _kMenuItemHeight,
|
||||
shrinkWrap: true,
|
||||
children: children,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -627,6 +634,7 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
|
|||
style: _textStyle.copyWith(color: Theme.of(context).hintColor),
|
||||
child: new IgnorePointer(
|
||||
child: widget.hint,
|
||||
ignoringSemantics: false,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
@ -681,10 +689,13 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
|
|||
);
|
||||
}
|
||||
|
||||
return new GestureDetector(
|
||||
onTap: _handleTap,
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: result
|
||||
return new Semantics(
|
||||
button: true,
|
||||
child: new GestureDetector(
|
||||
onTap: _handleTap,
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: result
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -365,7 +365,7 @@ class SemanticsData extends Diagnosticable {
|
|||
scrollExtentMax,
|
||||
scrollExtentMin,
|
||||
transform,
|
||||
customSemanticsActionIds,
|
||||
ui.hashList(customSemanticsActionIds),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -580,4 +580,102 @@ void main() {
|
|||
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('Dropdown button includes semantics', (WidgetTester tester) async {
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
const Key key = const Key('test');
|
||||
await tester.pumpWidget(buildFrame(
|
||||
buttonKey: key,
|
||||
value: null,
|
||||
items: menuItems,
|
||||
onChanged: (String _) {},
|
||||
hint: const Text('test'),
|
||||
));
|
||||
|
||||
// By default the hint contributes the label.
|
||||
expect(tester.getSemanticsData(find.byKey(key)), matchesSemanticsData(
|
||||
isButton: true,
|
||||
label: 'test',
|
||||
hasTapAction: true,
|
||||
));
|
||||
|
||||
await tester.pumpWidget(buildFrame(
|
||||
buttonKey: key,
|
||||
value: 'three',
|
||||
items: menuItems,
|
||||
onChanged: null,
|
||||
hint: const Text('test'),
|
||||
));
|
||||
|
||||
// Displays label of select item and is no longer tappable.
|
||||
expect(tester.getSemanticsData(find.byKey(key)), matchesSemanticsData(
|
||||
isButton: true,
|
||||
label: 'three',
|
||||
hasTapAction: true,
|
||||
));
|
||||
handle.dispose();
|
||||
});
|
||||
|
||||
testWidgets('Dropdown menu includes semantics', (WidgetTester tester) async {
|
||||
final SemanticsTester semantics = new SemanticsTester(tester);
|
||||
const Key key = const Key('test');
|
||||
await tester.pumpWidget(buildFrame(
|
||||
buttonKey: key,
|
||||
value: null,
|
||||
items: menuItems,
|
||||
));
|
||||
await tester.tap(find.byKey(key));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(semantics, hasSemantics(new TestSemantics.root(
|
||||
children: <TestSemantics>[
|
||||
new TestSemantics.rootChild(
|
||||
children: <TestSemantics>[
|
||||
new TestSemantics(
|
||||
flags: <SemanticsFlag>[
|
||||
SemanticsFlag.scopesRoute,
|
||||
SemanticsFlag.namesRoute,
|
||||
],
|
||||
label: 'Popup menu',
|
||||
children: <TestSemantics>[
|
||||
new TestSemantics(
|
||||
children: <TestSemantics>[
|
||||
new TestSemantics(
|
||||
children: <TestSemantics>[
|
||||
new TestSemantics(
|
||||
label: 'one',
|
||||
textDirection: TextDirection.ltr,
|
||||
tags: <SemanticsTag>[const SemanticsTag('RenderViewport.twoPane')],
|
||||
actions: <SemanticsAction>[SemanticsAction.tap],
|
||||
),
|
||||
new TestSemantics(
|
||||
label: 'two',
|
||||
textDirection: TextDirection.ltr,
|
||||
tags: <SemanticsTag>[const SemanticsTag('RenderViewport.twoPane')],
|
||||
actions: <SemanticsAction>[SemanticsAction.tap],
|
||||
),
|
||||
new TestSemantics(
|
||||
label: 'three',
|
||||
textDirection: TextDirection.ltr,
|
||||
tags: <SemanticsTag>[const SemanticsTag('RenderViewport.twoPane')],
|
||||
actions: <SemanticsAction>[SemanticsAction.tap],
|
||||
),
|
||||
new TestSemantics(
|
||||
label: 'four',
|
||||
textDirection: TextDirection.ltr,
|
||||
tags: <SemanticsTag>[const SemanticsTag('RenderViewport.twoPane')],
|
||||
actions: <SemanticsAction>[SemanticsAction.tap],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
), ignoreId: true, ignoreRect: true, ignoreTransform: true));
|
||||
semantics.dispose();
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue