refactor material banner and fix focus issue (#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
This commit is contained in:
parent
767bfd31da
commit
d528c7903f
@ -25,38 +25,43 @@ class MainWidget extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MainWidgetState extends State<MainWidget> {
|
class MainWidgetState extends State<MainWidget> {
|
||||||
double currentSliderValue = 20;
|
|
||||||
ScaffoldFeatureController<MaterialBanner, MaterialBannerClosedReason>?
|
final FocusNode dismissButtonFocusNode = FocusNode();
|
||||||
controller;
|
final FocusNode showButtonFocusNode = FocusNode();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
dismissButtonFocusNode.dispose();
|
||||||
|
showButtonFocusNode.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void hideBanner() {
|
||||||
|
ScaffoldMessenger.of(context).hideCurrentMaterialBanner();
|
||||||
|
showButtonFocusNode.requestFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void showBanner() {
|
||||||
|
ScaffoldMessenger.of(context).showMaterialBanner(
|
||||||
|
MaterialBanner(
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
content: const Text('Hello, I am a Material Banner'),
|
||||||
|
leading: const Icon(Icons.agriculture_outlined),
|
||||||
|
backgroundColor: Colors.yellowAccent,
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
focusNode: dismissButtonFocusNode,
|
||||||
|
onPressed: hideBanner,
|
||||||
|
child: const Text('DISMISS'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
dismissButtonFocusNode.requestFocus();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
VoidCallback? onPress;
|
|
||||||
if (controller == null) {
|
|
||||||
onPress = () {
|
|
||||||
setState(() {
|
|
||||||
controller = ScaffoldMessenger.of(context).showMaterialBanner(
|
|
||||||
MaterialBanner(
|
|
||||||
padding: const EdgeInsets.all(20),
|
|
||||||
content: const Text('Hello, I am a Material Banner'),
|
|
||||||
leading: const Icon(Icons.agriculture_outlined),
|
|
||||||
backgroundColor: Colors.green,
|
|
||||||
actions: <Widget>[
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
controller!.close();
|
|
||||||
setState(() {
|
|
||||||
controller = null;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: const Text('DISMISS'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||||
@ -64,7 +69,8 @@ class MainWidgetState extends State<MainWidget> {
|
|||||||
),
|
),
|
||||||
body: Center(
|
body: Center(
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: onPress,
|
focusNode: showButtonFocusNode,
|
||||||
|
onPressed: showBanner,
|
||||||
child: const Text('Show a MaterialBanner'),
|
child: const Text('Show a MaterialBanner'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'package:a11y_assessments/use_cases/material_banner.dart';
|
import 'package:a11y_assessments/use_cases/material_banner.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
import 'test_utils.dart';
|
import 'test_utils.dart';
|
||||||
@ -21,6 +22,26 @@ void main() {
|
|||||||
expect(find.text('Hello, I am a Material Banner'), findsNothing);
|
expect(find.text('Hello, I am a Material Banner'), findsNothing);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('dismiss button focused on banner open', (WidgetTester tester) async {
|
||||||
|
await pumpsUseCase(tester, MaterialBannerUseCase());
|
||||||
|
await tester.tap(find.text('Show a MaterialBanner'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
final TextButton dismissButtonFinder = tester.widget<TextButton>(find.byType(TextButton));
|
||||||
|
expect(dismissButtonFinder.focusNode!.hasFocus, isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('show button focused on banner close', (WidgetTester tester) async {
|
||||||
|
await pumpsUseCase(tester, MaterialBannerUseCase());
|
||||||
|
await tester.tap(find.text('Show a MaterialBanner'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(find.byType(TextButton));
|
||||||
|
|
||||||
|
final ElevatedButton showButtonFinder = tester.widget<ElevatedButton>(find.byType(ElevatedButton));
|
||||||
|
expect(showButtonFinder.focusNode!.hasFocus, isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('material banner has one h1 tag', (WidgetTester tester) async {
|
testWidgets('material banner has one h1 tag', (WidgetTester tester) async {
|
||||||
await pumpsUseCase(tester, MaterialBannerUseCase());
|
await pumpsUseCase(tester, MaterialBannerUseCase());
|
||||||
final Finder findHeadingLevelOnes = find.bySemanticsLabel('MaterialBanner Demo');
|
final Finder findHeadingLevelOnes = find.bySemanticsLabel('MaterialBanner Demo');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user