@@ -295,6 +295,7 @@ class NavigationDestination extends StatelessWidget {
295
295
this .selectedIcon,
296
296
required this .label,
297
297
this .tooltip,
298
+ this .enabled = true ,
298
299
});
299
300
300
301
/// The [Widget] (usually an [Icon] ) that's displayed for this
@@ -333,11 +334,17 @@ class NavigationDestination extends StatelessWidget {
333
334
/// Defaults to null, in which case the [label] text will be used.
334
335
final String ? tooltip;
335
336
337
+ /// Indicates that this destination is selectable.
338
+ ///
339
+ /// Defaults to true.
340
+ final bool enabled;
341
+
336
342
@override
337
343
Widget build (BuildContext context) {
338
344
final _NavigationDestinationInfo info = _NavigationDestinationInfo .of (context);
339
345
const Set <MaterialState > selectedState = < MaterialState > {MaterialState .selected};
340
346
const Set <MaterialState > unselectedState = < MaterialState > {};
347
+ const Set <MaterialState > disabledState = < MaterialState > {MaterialState .disabled};
341
348
342
349
final NavigationBarThemeData navigationBarTheme = NavigationBarTheme .of (context);
343
350
final NavigationBarThemeData defaults = _defaultsFor (context);
@@ -346,15 +353,24 @@ class NavigationDestination extends StatelessWidget {
346
353
return _NavigationDestinationBuilder (
347
354
label: label,
348
355
tooltip: tooltip,
356
+ enabled: enabled,
349
357
buildIcon: (BuildContext context) {
358
+ final IconThemeData selectedIconTheme =
359
+ navigationBarTheme.iconTheme? .resolve (selectedState)
360
+ ?? defaults.iconTheme! .resolve (selectedState)! ;
361
+ final IconThemeData unselectedIconTheme =
362
+ navigationBarTheme.iconTheme? .resolve (unselectedState)
363
+ ?? defaults.iconTheme! .resolve (unselectedState)! ;
364
+ final IconThemeData disabledIconTheme =
365
+ navigationBarTheme.iconTheme? .resolve (disabledState)
366
+ ?? defaults.iconTheme! .resolve (disabledState)! ;
367
+
350
368
final Widget selectedIconWidget = IconTheme .merge (
351
- data: navigationBarTheme.iconTheme? .resolve (selectedState)
352
- ?? defaults.iconTheme! .resolve (selectedState)! ,
369
+ data: enabled ? selectedIconTheme : disabledIconTheme,
353
370
child: selectedIcon ?? icon,
354
371
);
355
372
final Widget unselectedIconWidget = IconTheme .merge (
356
- data: navigationBarTheme.iconTheme? .resolve (unselectedState)
357
- ?? defaults.iconTheme! .resolve (unselectedState)! ,
373
+ data: enabled ? unselectedIconTheme : disabledIconTheme,
358
374
child: icon,
359
375
);
360
376
@@ -382,7 +398,15 @@ class NavigationDestination extends StatelessWidget {
382
398
?? defaults.labelTextStyle! .resolve (selectedState);
383
399
final TextStyle ? effectiveUnselectedLabelTextStyle = navigationBarTheme.labelTextStyle? .resolve (unselectedState)
384
400
?? defaults.labelTextStyle! .resolve (unselectedState);
385
- final TextStyle ? textStyle = _isForwardOrCompleted (animation) ? effectiveSelectedLabelTextStyle : effectiveUnselectedLabelTextStyle;
401
+ final TextStyle ? effectiveDisabledLabelTextStyle = navigationBarTheme.labelTextStyle? .resolve (disabledState)
402
+ ?? defaults.labelTextStyle! .resolve (disabledState);
403
+
404
+ final TextStyle ? textStyle = enabled
405
+ ? _isForwardOrCompleted (animation)
406
+ ? effectiveSelectedLabelTextStyle
407
+ : effectiveUnselectedLabelTextStyle
408
+ : effectiveDisabledLabelTextStyle;
409
+
386
410
return Padding (
387
411
padding: const EdgeInsets .only (top: 4 ),
388
412
child: MediaQuery .withClampedTextScaling (
@@ -416,6 +440,7 @@ class _NavigationDestinationBuilder extends StatefulWidget {
416
440
required this .buildLabel,
417
441
required this .label,
418
442
this .tooltip,
443
+ this .enabled = true ,
419
444
});
420
445
421
446
/// Builds the icon for a destination in a [NavigationBar] .
@@ -454,6 +479,11 @@ class _NavigationDestinationBuilder extends StatefulWidget {
454
479
/// Defaults to null, in which case the [label] text will be used.
455
480
final String ? tooltip;
456
481
482
+ /// Indicates that this destination is selectable.
483
+ ///
484
+ /// Defaults to true.
485
+ final bool enabled;
486
+
457
487
@override
458
488
State <_NavigationDestinationBuilder > createState () => _NavigationDestinationBuilderState ();
459
489
}
@@ -474,7 +504,7 @@ class _NavigationDestinationBuilderState extends State<_NavigationDestinationBui
474
504
iconKey: iconKey,
475
505
labelBehavior: info.labelBehavior,
476
506
customBorder: navigationBarTheme.indicatorShape ?? defaults.indicatorShape,
477
- onTap: info.onTap,
507
+ onTap: widget.enabled ? info.onTap : null ,
478
508
child: Row (
479
509
children: < Widget > [
480
510
Expanded (
@@ -1319,9 +1349,11 @@ class _NavigationBarDefaultsM3 extends NavigationBarThemeData {
1319
1349
return MaterialStateProperty .resolveWith ((Set <MaterialState > states) {
1320
1350
return IconThemeData (
1321
1351
size: 24.0 ,
1322
- color: states.contains (MaterialState .selected)
1323
- ? _colors.onSecondaryContainer
1324
- : _colors.onSurfaceVariant,
1352
+ color: states.contains (MaterialState .disabled)
1353
+ ? _colors.onSurfaceVariant.withOpacity (0.38 )
1354
+ : states.contains (MaterialState .selected)
1355
+ ? _colors.onSecondaryContainer
1356
+ : _colors.onSurfaceVariant,
1325
1357
);
1326
1358
});
1327
1359
}
@@ -1332,9 +1364,11 @@ class _NavigationBarDefaultsM3 extends NavigationBarThemeData {
1332
1364
@override MaterialStateProperty <TextStyle ?>? get labelTextStyle {
1333
1365
return MaterialStateProperty .resolveWith ((Set <MaterialState > states) {
1334
1366
final TextStyle style = _textTheme.labelMedium! ;
1335
- return style.apply (color: states.contains (MaterialState .selected)
1336
- ? _colors.onSurface
1337
- : _colors.onSurfaceVariant
1367
+ return style.apply (color: states.contains (MaterialState .disabled)
1368
+ ? _colors.onSurfaceVariant.withOpacity (0.38 )
1369
+ : states.contains (MaterialState .selected)
1370
+ ? _colors.onSurface
1371
+ : _colors.onSurfaceVariant
1338
1372
);
1339
1373
});
1340
1374
}
0 commit comments