Skip to content

Commit d528c79

Browse files
authored
refactor material banner and fix focus issue (flutter#152646)
- Refactored material banner setup to make it more simple and stateless - Added focusNode to where the dismiss button focuses automatically when banner is shown Before: https://screencast.googleplex.com/cast/NTI4OTMxNjU2MDQwNDQ4MHw2ODdiMmYwOC1hMg After: https://screencast.googleplex.com/cast/NjAzNTY4NDA2NTI4MDAwMHwyNTRjMWUxMi0zMA fixes b/346646604
1 parent 767bfd3 commit d528c79

File tree

2 files changed

+57
-30
lines changed

2 files changed

+57
-30
lines changed

dev/a11y_assessments/lib/use_cases/material_banner.dart

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,46 +25,52 @@ class MainWidget extends StatefulWidget {
2525
}
2626

2727
class MainWidgetState extends State<MainWidget> {
28-
double currentSliderValue = 20;
29-
ScaffoldFeatureController<MaterialBanner, MaterialBannerClosedReason>?
30-
controller;
28+
29+
final FocusNode dismissButtonFocusNode = FocusNode();
30+
final FocusNode showButtonFocusNode = FocusNode();
31+
32+
@override
33+
void dispose() {
34+
dismissButtonFocusNode.dispose();
35+
showButtonFocusNode.dispose();
36+
super.dispose();
37+
}
38+
39+
void hideBanner() {
40+
ScaffoldMessenger.of(context).hideCurrentMaterialBanner();
41+
showButtonFocusNode.requestFocus();
42+
}
43+
44+
void showBanner() {
45+
ScaffoldMessenger.of(context).showMaterialBanner(
46+
MaterialBanner(
47+
padding: const EdgeInsets.all(20),
48+
content: const Text('Hello, I am a Material Banner'),
49+
leading: const Icon(Icons.agriculture_outlined),
50+
backgroundColor: Colors.yellowAccent,
51+
actions: <Widget>[
52+
TextButton(
53+
focusNode: dismissButtonFocusNode,
54+
onPressed: hideBanner,
55+
child: const Text('DISMISS'),
56+
),
57+
],
58+
),
59+
);
60+
dismissButtonFocusNode.requestFocus();
61+
}
3162

3263
@override
3364
Widget build(BuildContext context) {
34-
VoidCallback? onPress;
35-
if (controller == null) {
36-
onPress = () {
37-
setState(() {
38-
controller = ScaffoldMessenger.of(context).showMaterialBanner(
39-
MaterialBanner(
40-
padding: const EdgeInsets.all(20),
41-
content: const Text('Hello, I am a Material Banner'),
42-
leading: const Icon(Icons.agriculture_outlined),
43-
backgroundColor: Colors.green,
44-
actions: <Widget>[
45-
TextButton(
46-
onPressed: () {
47-
controller!.close();
48-
setState(() {
49-
controller = null;
50-
});
51-
},
52-
child: const Text('DISMISS'),
53-
),
54-
],
55-
),
56-
);
57-
});
58-
};
59-
}
6065
return Scaffold(
6166
appBar: AppBar(
6267
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
6368
title: Semantics(headingLevel: 1, child: const Text('MaterialBanner Demo')),
6469
),
6570
body: Center(
6671
child: ElevatedButton(
67-
onPressed: onPress,
72+
focusNode: showButtonFocusNode,
73+
onPressed: showBanner,
6874
child: const Text('Show a MaterialBanner'),
6975
),
7076
),

dev/a11y_assessments/test/material_banner_test.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// found in the LICENSE file.
44

55
import 'package:a11y_assessments/use_cases/material_banner.dart';
6+
import 'package:flutter/material.dart';
67
import 'package:flutter_test/flutter_test.dart';
78

89
import 'test_utils.dart';
@@ -21,6 +22,26 @@ void main() {
2122
expect(find.text('Hello, I am a Material Banner'), findsNothing);
2223
});
2324

25+
testWidgets('dismiss button focused on banner open', (WidgetTester tester) async {
26+
await pumpsUseCase(tester, MaterialBannerUseCase());
27+
await tester.tap(find.text('Show a MaterialBanner'));
28+
await tester.pumpAndSettle();
29+
30+
final TextButton dismissButtonFinder = tester.widget<TextButton>(find.byType(TextButton));
31+
expect(dismissButtonFinder.focusNode!.hasFocus, isTrue);
32+
});
33+
34+
testWidgets('show button focused on banner close', (WidgetTester tester) async {
35+
await pumpsUseCase(tester, MaterialBannerUseCase());
36+
await tester.tap(find.text('Show a MaterialBanner'));
37+
await tester.pumpAndSettle();
38+
39+
await tester.tap(find.byType(TextButton));
40+
41+
final ElevatedButton showButtonFinder = tester.widget<ElevatedButton>(find.byType(ElevatedButton));
42+
expect(showButtonFinder.focusNode!.hasFocus, isTrue);
43+
});
44+
2445
testWidgets('material banner has one h1 tag', (WidgetTester tester) async {
2546
await pumpsUseCase(tester, MaterialBannerUseCase());
2647
final Finder findHeadingLevelOnes = find.bySemanticsLabel('MaterialBanner Demo');

0 commit comments

Comments
 (0)