mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
fix ExpansionPanelList merge the header semantics when it is not necessart (#33808)
This commit is contained in:
parent
00d95e6212
commit
9d38db421c
@ -7,6 +7,7 @@ import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'expand_icon.dart';
|
||||
import 'ink_well.dart';
|
||||
import 'material_localizations.dart';
|
||||
import 'mergeable_material.dart';
|
||||
import 'theme.dart';
|
||||
|
||||
@ -446,7 +447,26 @@ class _ExpansionPanelListState extends State<ExpansionPanelList> {
|
||||
context,
|
||||
_isChildExpanded(index),
|
||||
);
|
||||
final Row header = Row(
|
||||
|
||||
Widget expandIconContainer = Container(
|
||||
margin: const EdgeInsetsDirectional.only(end: 8.0),
|
||||
child: ExpandIcon(
|
||||
isExpanded: _isChildExpanded(index),
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
onPressed: !child.canTapOnHeader
|
||||
? (bool isExpanded) => _handlePressed(isExpanded, index)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
if (!child.canTapOnHeader) {
|
||||
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
||||
expandIconContainer = Semantics(
|
||||
label: _isChildExpanded(index)? localizations.expandedIconTapHint : localizations.collapsedIconTapHint,
|
||||
container: true,
|
||||
child: expandIconContainer
|
||||
);
|
||||
}
|
||||
Widget header = Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: AnimatedContainer(
|
||||
@ -459,32 +479,23 @@ class _ExpansionPanelListState extends State<ExpansionPanelList> {
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
margin: const EdgeInsetsDirectional.only(end: 8.0),
|
||||
child: ExpandIcon(
|
||||
isExpanded: _isChildExpanded(index),
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
onPressed: !child.canTapOnHeader
|
||||
? (bool isExpanded) => _handlePressed(isExpanded, index)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
expandIconContainer,
|
||||
],
|
||||
);
|
||||
|
||||
if (child.canTapOnHeader) {
|
||||
header = MergeSemantics(
|
||||
child: InkWell(
|
||||
onTap: () => _handlePressed(_isChildExpanded(index), index),
|
||||
child: header,
|
||||
)
|
||||
);
|
||||
}
|
||||
items.add(
|
||||
MaterialSlice(
|
||||
key: _SaltedKey<BuildContext, int>(context, index * 2),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
MergeSemantics(
|
||||
child: child.canTapOnHeader
|
||||
? InkWell(
|
||||
onTap: () => _handlePressed(_isChildExpanded(index), index),
|
||||
child: header,
|
||||
)
|
||||
: header,
|
||||
),
|
||||
header,
|
||||
AnimatedCrossFade(
|
||||
firstChild: Container(height: 0.0),
|
||||
secondChild: child.body,
|
||||
|
||||
@ -54,6 +54,49 @@ class _SimpleExpansionPanelListTestWidgetState extends State<SimpleExpansionPane
|
||||
}
|
||||
}
|
||||
|
||||
class ExpansionPanelListSemanticsTest extends StatefulWidget {
|
||||
const ExpansionPanelListSemanticsTest({this.headerKey});
|
||||
|
||||
final Key headerKey;
|
||||
|
||||
@override
|
||||
ExpansionPanelListSemanticsTestState createState() => ExpansionPanelListSemanticsTestState();
|
||||
}
|
||||
|
||||
class ExpansionPanelListSemanticsTestState extends State<ExpansionPanelListSemanticsTest> {
|
||||
bool headerTapped = false;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView(
|
||||
children: <Widget>[
|
||||
ExpansionPanelList(
|
||||
children: <ExpansionPanel>[
|
||||
ExpansionPanel(
|
||||
canTapOnHeader: false,
|
||||
headerBuilder: (BuildContext context, bool isExpanded) {
|
||||
return MergeSemantics(
|
||||
key: widget.headerKey,
|
||||
child: GestureDetector(
|
||||
onTap: () => headerTapped = true,
|
||||
child: const Text.rich(
|
||||
TextSpan(
|
||||
text:'head1',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
body: Container(
|
||||
child: const Placeholder(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('ExpansionPanelList test', (WidgetTester tester) async {
|
||||
int index;
|
||||
@ -91,7 +134,7 @@ void main() {
|
||||
box = tester.renderObject(find.byType(ExpansionPanelList));
|
||||
expect(box.size.height, equals(oldHeight));
|
||||
|
||||
// now expand the child panel
|
||||
// Now, expand the child panel.
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: SingleChildScrollView(
|
||||
@ -121,6 +164,52 @@ void main() {
|
||||
expect(box.size.height - oldHeight, greaterThanOrEqualTo(100.0)); // 100 + some margin
|
||||
});
|
||||
|
||||
testWidgets('ExpansionPanelList does not merge header when canTapOnHeader is false', (WidgetTester tester) async {
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
final Key headerKey = UniqueKey();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: ExpansionPanelListSemanticsTest(headerKey: headerKey),
|
||||
),
|
||||
);
|
||||
|
||||
// Make sure custom gesture detector widget is clickable.
|
||||
await tester.tap(find.text('head1'));
|
||||
await tester.pump();
|
||||
|
||||
final ExpansionPanelListSemanticsTestState state =
|
||||
tester.state(find.byType(ExpansionPanelListSemanticsTest));
|
||||
expect(state.headerTapped, true);
|
||||
|
||||
// Check the expansion icon semantics does not merged with header widget.
|
||||
final Finder expansionIcon = find.descendant(
|
||||
of: find.ancestor(
|
||||
of: find.byKey(headerKey),
|
||||
matching: find.byType(Row),
|
||||
),
|
||||
matching: find.byType(ExpandIcon),
|
||||
);
|
||||
expect(tester.getSemantics(expansionIcon), matchesSemantics(
|
||||
label: 'Expand',
|
||||
isButton: true,
|
||||
hasEnabledState: true,
|
||||
isEnabled: true,
|
||||
hasTapAction: true,
|
||||
));
|
||||
|
||||
// Check custom header widget semantics is preserved.
|
||||
final Finder headerWidget = find.descendant(
|
||||
of: find.byKey(headerKey),
|
||||
matching: find.byType(RichText),
|
||||
);
|
||||
expect(tester.getSemantics(headerWidget), matchesSemantics(
|
||||
label: 'head1',
|
||||
hasTapAction: true,
|
||||
));
|
||||
|
||||
handle.dispose();
|
||||
});
|
||||
|
||||
testWidgets('Multiple Panel List test', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
@ -798,7 +887,7 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
|
||||
testWidgets('Panel header has semantics', (WidgetTester tester) async {
|
||||
testWidgets('Panel header has semantics, canTapOnHeader = false ', (WidgetTester tester) async {
|
||||
const Key expandedKey = Key('expanded');
|
||||
const Key collapsedKey = Key('collapsed');
|
||||
const DefaultMaterialLocalizations localizations = DefaultMaterialLocalizations();
|
||||
@ -832,8 +921,16 @@ void main() {
|
||||
),
|
||||
);
|
||||
|
||||
expect(tester.getSemantics(find.byKey(expandedKey)), matchesSemantics(
|
||||
label: 'Expanded',
|
||||
// Check the semantics of [ExpanIcon] for expanded panel.
|
||||
final Finder expandedIcon = find.descendant(
|
||||
of: find.ancestor(
|
||||
of: find.byKey(expandedKey),
|
||||
matching: find.byType(Row),
|
||||
),
|
||||
matching: find.byType(ExpandIcon),
|
||||
);
|
||||
expect(tester.getSemantics(expandedIcon), matchesSemantics(
|
||||
label: 'Collapse',
|
||||
isButton: true,
|
||||
hasEnabledState: true,
|
||||
isEnabled: true,
|
||||
@ -841,8 +938,22 @@ void main() {
|
||||
onTapHint: localizations.expandedIconTapHint,
|
||||
));
|
||||
|
||||
expect(tester.getSemantics(find.byKey(collapsedKey)), matchesSemantics(
|
||||
label: 'Collapsed',
|
||||
// Check the semantics of the header widget for expanded panel.
|
||||
final Finder expandedHeader = find.byKey(expandedKey);
|
||||
expect(tester.getSemantics(expandedHeader), matchesSemantics(
|
||||
label: 'Expanded',
|
||||
));
|
||||
|
||||
// Check the semantics of [ExpanIcon] for collapsed panel.
|
||||
final Finder collapsedIcon = find.descendant(
|
||||
of: find.ancestor(
|
||||
of: find.byKey(collapsedKey),
|
||||
matching: find.byType(Row),
|
||||
),
|
||||
matching: find.byType(ExpandIcon),
|
||||
);
|
||||
expect(tester.getSemantics(collapsedIcon), matchesSemantics(
|
||||
label: 'Expand',
|
||||
isButton: true,
|
||||
hasEnabledState: true,
|
||||
isEnabled: true,
|
||||
@ -850,6 +961,64 @@ void main() {
|
||||
onTapHint: localizations.collapsedIconTapHint,
|
||||
));
|
||||
|
||||
// Check the semantics of the header widget for expanded panel.
|
||||
final Finder collapsedHeader = find.byKey(collapsedKey);
|
||||
expect(tester.getSemantics(collapsedHeader), matchesSemantics(
|
||||
label: 'Collapsed',
|
||||
));
|
||||
|
||||
handle.dispose();
|
||||
});
|
||||
|
||||
testWidgets('Panel header has semantics, canTapOnHeader = true', (WidgetTester tester) async {
|
||||
const Key expandedKey = Key('expanded');
|
||||
const Key collapsedKey = Key('collapsed');
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
final List<ExpansionPanel> _demoItems = <ExpansionPanel>[
|
||||
ExpansionPanel(
|
||||
headerBuilder: (BuildContext context, bool isExpanded) {
|
||||
return const Text('Expanded', key: expandedKey);
|
||||
},
|
||||
canTapOnHeader: true,
|
||||
body: const SizedBox(height: 100.0),
|
||||
isExpanded: true,
|
||||
),
|
||||
ExpansionPanel(
|
||||
headerBuilder: (BuildContext context, bool isExpanded) {
|
||||
return const Text('Collapsed', key: collapsedKey);
|
||||
},
|
||||
canTapOnHeader: true,
|
||||
body: const SizedBox(height: 100.0),
|
||||
isExpanded: false,
|
||||
),
|
||||
];
|
||||
|
||||
final ExpansionPanelList _expansionList = ExpansionPanelList(
|
||||
children: _demoItems,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: SingleChildScrollView(
|
||||
child: _expansionList,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(tester.getSemantics(find.byKey(expandedKey)), matchesSemantics(
|
||||
label: 'Expanded',
|
||||
isButton: true,
|
||||
hasEnabledState: true,
|
||||
hasTapAction: true,
|
||||
));
|
||||
|
||||
expect(tester.getSemantics(find.byKey(collapsedKey)), matchesSemantics(
|
||||
label: 'Collapsed',
|
||||
isButton: true,
|
||||
hasEnabledState: true,
|
||||
hasTapAction: true,
|
||||
));
|
||||
|
||||
handle.dispose();
|
||||
});
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user