@@ -26,25 +26,28 @@ class FirstComponentList extends StatelessWidget {
26
26
27
27
@override
28
28
Widget build (BuildContext context) {
29
- return ListView (
30
- padding: showSecondList
31
- ? const EdgeInsetsDirectional .only (end: smallSpacing)
32
- : EdgeInsets .zero,
33
- children: [
34
- const Actions (),
35
- colDivider,
36
- const Communication (),
37
- colDivider,
38
- const Containment (),
39
- if (! showSecondList) ...[
40
- colDivider,
41
- Navigation (scaffoldKey: scaffoldKey),
29
+ // Fully traverse this list before moving on.
30
+ return FocusTraversalGroup (
31
+ child: ListView (
32
+ padding: showSecondList
33
+ ? const EdgeInsetsDirectional .only (end: smallSpacing)
34
+ : EdgeInsets .zero,
35
+ children: [
36
+ const Actions (),
42
37
colDivider,
43
- const Selection (),
38
+ const Communication (),
44
39
colDivider,
45
- const TextInputs ()
40
+ const Containment (),
41
+ if (! showSecondList) ...[
42
+ colDivider,
43
+ Navigation (scaffoldKey: scaffoldKey),
44
+ colDivider,
45
+ const Selection (),
46
+ colDivider,
47
+ const TextInputs ()
48
+ ],
46
49
],
47
- ] ,
50
+ ) ,
48
51
);
49
52
}
50
53
}
@@ -59,15 +62,18 @@ class SecondComponentList extends StatelessWidget {
59
62
60
63
@override
61
64
Widget build (BuildContext context) {
62
- return ListView (
63
- padding: const EdgeInsetsDirectional .only (end: smallSpacing),
64
- children: < Widget > [
65
- Navigation (scaffoldKey: scaffoldKey),
66
- colDivider,
67
- const Selection (),
68
- colDivider,
69
- const TextInputs (),
70
- ],
65
+ // Fully traverse this list before moving on.
66
+ return FocusTraversalGroup (
67
+ child: ListView (
68
+ padding: const EdgeInsetsDirectional .only (end: smallSpacing),
69
+ children: < Widget > [
70
+ Navigation (scaffoldKey: scaffoldKey),
71
+ colDivider,
72
+ const Selection (),
73
+ colDivider,
74
+ const TextInputs (),
75
+ ],
76
+ ),
71
77
);
72
78
}
73
79
}
@@ -1011,13 +1017,13 @@ class NavigationBars extends StatefulWidget {
1011
1017
this .onSelectItem,
1012
1018
required this .selectedIndex,
1013
1019
required this .isExampleBar,
1014
- this .isBadgeExample,
1020
+ this .isBadgeExample = false ,
1015
1021
});
1016
1022
1017
1023
final void Function (int )? onSelectItem;
1018
1024
final int selectedIndex;
1019
1025
final bool isExampleBar;
1020
- final bool ? isBadgeExample;
1026
+ final bool isBadgeExample;
1021
1027
1022
1028
@override
1023
1029
State <NavigationBars > createState () => _NavigationBarsState ();
@@ -1042,23 +1048,26 @@ class _NavigationBarsState extends State<NavigationBars> {
1042
1048
1043
1049
@override
1044
1050
Widget build (BuildContext context) {
1045
- bool isBadgeExample = widget.isBadgeExample ?? false ;
1046
- Widget navigationBar = NavigationBar (
1047
- selectedIndex: selectedIndex,
1048
- onDestinationSelected: (index) {
1049
- setState (() {
1050
- selectedIndex = index;
1051
- });
1052
- if (! widget.isExampleBar) widget.onSelectItem !(index);
1053
- },
1054
- destinations: widget.isExampleBar && isBadgeExample
1055
- ? barWithBadgeDestinations
1056
- : widget.isExampleBar
1057
- ? exampleBarDestinations
1058
- : appBarDestinations,
1051
+ // App NavigationBar should get first focus.
1052
+ Widget navigationBar = Focus (
1053
+ autofocus: ! (widget.isExampleBar || widget.isBadgeExample),
1054
+ child: NavigationBar (
1055
+ selectedIndex: selectedIndex,
1056
+ onDestinationSelected: (index) {
1057
+ setState (() {
1058
+ selectedIndex = index;
1059
+ });
1060
+ if (! widget.isExampleBar) widget.onSelectItem !(index);
1061
+ },
1062
+ destinations: widget.isExampleBar && widget.isBadgeExample
1063
+ ? barWithBadgeDestinations
1064
+ : widget.isExampleBar
1065
+ ? exampleBarDestinations
1066
+ : appBarDestinations,
1067
+ ),
1059
1068
);
1060
1069
1061
- if (widget.isExampleBar && isBadgeExample) {
1070
+ if (widget.isExampleBar && widget. isBadgeExample) {
1062
1071
navigationBar = ComponentDecoration (
1063
1072
label: 'Badges' ,
1064
1073
tooltipMessage: 'Use Badge or Badge.count' ,
@@ -2188,7 +2197,7 @@ class _SlidersState extends State<Sliders> {
2188
2197
}
2189
2198
}
2190
2199
2191
- class ComponentDecoration extends StatelessWidget {
2200
+ class ComponentDecoration extends StatefulWidget {
2192
2201
const ComponentDecoration ({
2193
2202
super .key,
2194
2203
required this .label,
@@ -2200,6 +2209,13 @@ class ComponentDecoration extends StatelessWidget {
2200
2209
final Widget child;
2201
2210
final String ? tooltipMessage;
2202
2211
2212
+ @override
2213
+ State <ComponentDecoration > createState () => _ComponentDecorationState ();
2214
+ }
2215
+
2216
+ class _ComponentDecorationState extends State <ComponentDecoration > {
2217
+ final focusNode = FocusNode ();
2218
+
2203
2219
@override
2204
2220
Widget build (BuildContext context) {
2205
2221
return RepaintBoundary (
@@ -2210,9 +2226,10 @@ class ComponentDecoration extends StatelessWidget {
2210
2226
Row (
2211
2227
mainAxisAlignment: MainAxisAlignment .center,
2212
2228
children: [
2213
- Text (label, style: Theme .of (context).textTheme.titleSmall),
2229
+ Text (widget.label,
2230
+ style: Theme .of (context).textTheme.titleSmall),
2214
2231
Tooltip (
2215
- message: tooltipMessage,
2232
+ message: widget. tooltipMessage,
2216
2233
child: const Padding (
2217
2234
padding: EdgeInsets .symmetric (horizontal: 5.0 ),
2218
2235
child: Icon (Icons .info_outline, size: 16 )),
@@ -2222,18 +2239,32 @@ class ComponentDecoration extends StatelessWidget {
2222
2239
ConstrainedBox (
2223
2240
constraints:
2224
2241
const BoxConstraints .tightFor (width: widthConstraint),
2225
- child: Card (
2226
- elevation: 0 ,
2227
- shape: RoundedRectangleBorder (
2228
- side: BorderSide (
2229
- color: Theme .of (context).colorScheme.outlineVariant,
2242
+ // Tapping within the a component card should request focus
2243
+ // for that component's children.
2244
+ child: Focus (
2245
+ focusNode: focusNode,
2246
+ canRequestFocus: true ,
2247
+ child: GestureDetector (
2248
+ onTapDown: (_) {
2249
+ focusNode.requestFocus ();
2250
+ },
2251
+ behavior: HitTestBehavior .opaque,
2252
+ child: Card (
2253
+ elevation: 0 ,
2254
+ shape: RoundedRectangleBorder (
2255
+ side: BorderSide (
2256
+ color: Theme .of (context).colorScheme.outlineVariant,
2257
+ ),
2258
+ borderRadius: const BorderRadius .all (Radius .circular (12 )),
2259
+ ),
2260
+ child: Padding (
2261
+ padding: const EdgeInsets .symmetric (
2262
+ horizontal: 5.0 , vertical: 20.0 ),
2263
+ child: Center (
2264
+ child: widget.child,
2265
+ ),
2266
+ ),
2230
2267
),
2231
- borderRadius: const BorderRadius .all (Radius .circular (12 )),
2232
- ),
2233
- child: Padding (
2234
- padding: const EdgeInsets .symmetric (
2235
- horizontal: 5.0 , vertical: 20.0 ),
2236
- child: Center (child: child),
2237
2268
),
2238
2269
),
2239
2270
),
@@ -2253,19 +2284,22 @@ class ComponentGroupDecoration extends StatelessWidget {
2253
2284
2254
2285
@override
2255
2286
Widget build (BuildContext context) {
2256
- return Card (
2257
- margin: EdgeInsets .zero,
2258
- elevation: 0 ,
2259
- color: Theme .of (context).colorScheme.surfaceVariant.withOpacity (0.3 ),
2260
- child: Padding (
2261
- padding: const EdgeInsets .symmetric (vertical: 20.0 ),
2262
- child: Center (
2263
- child: Column (
2264
- children: [
2265
- Text (label, style: Theme .of (context).textTheme.titleLarge),
2266
- colDivider,
2267
- ...children
2268
- ],
2287
+ // Fully traverse this component group before moving on
2288
+ return FocusTraversalGroup (
2289
+ child: Card (
2290
+ margin: EdgeInsets .zero,
2291
+ elevation: 0 ,
2292
+ color: Theme .of (context).colorScheme.surfaceVariant.withOpacity (0.3 ),
2293
+ child: Padding (
2294
+ padding: const EdgeInsets .symmetric (vertical: 20.0 ),
2295
+ child: Center (
2296
+ child: Column (
2297
+ children: [
2298
+ Text (label, style: Theme .of (context).textTheme.titleLarge),
2299
+ colDivider,
2300
+ ...children
2301
+ ],
2302
+ ),
2269
2303
),
2270
2304
),
2271
2305
),
0 commit comments