Skip to content

Commit 2c49369

Browse files
authored
[flutter_adaptive_scaffold] Map NavigationsRails destinations and use group and labelType (#7310)
*List which issues are fixed by this PR. You must list at least one issue.* flutter/flutter#141060 flutter/flutter#115235
1 parent eee589e commit 2c49369

4 files changed

Lines changed: 157 additions & 50 deletions

File tree

packages/flutter_adaptive_scaffold/CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
## NEXT
1+
## 0.1.12
22

33
* Updates minimum supported SDK version to Flutter 3.22/Dart 3.4.
44
* Updates minimum supported SDK version to Flutter 3.19/Dart 3.3.
5+
* Expose `labelType` for NavigationRails.
6+
* Add `navigationRailDestinationBuilder` to apply custom Destinations.
7+
* Add `groupAlignment` property to change alignment.
8+
* Set `navRailTheme` when using the Drawer just like the other NavigationRails.
59

610
## 0.1.11+1
711

packages/flutter_adaptive_scaffold/lib/src/adaptive_scaffold.dart

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ const double kMaterialMediumMinMargin = 12;
2424
/// design 3 spec.
2525
const double kMaterialExpandedMinMargin = 32;
2626

27+
/// Signature for a builder used by [AdaptiveScaffold.navigationRailDestinationBuilder] that converts a
28+
/// [NavigationDestination] to a [NavigationRailDestination].
29+
typedef NavigationRailDestinationBuilder = NavigationRailDestination Function(
30+
int index,
31+
NavigationDestination destination,
32+
);
33+
2734
/// Implements the basic visual layout structure for
2835
/// [Material Design 3](https://m3.material.io/foundations/adaptive-design/overview)
2936
/// that adapts to a variety of screens.
@@ -103,6 +110,8 @@ class AdaptiveScaffold extends StatefulWidget {
103110
this.navigationRailWidth = 72,
104111
this.extendedNavigationRailWidth = 192,
105112
this.appBarBreakpoint,
113+
this.navigationRailDestinationBuilder,
114+
this.groupAlignment,
106115
}) : assert(
107116
destinations.length >= 2,
108117
'At least two destinations are required',
@@ -129,6 +138,9 @@ class AdaptiveScaffold extends StatefulWidget {
129138
/// navigation rail at the largest breakpoint.
130139
final Widget? trailingNavRail;
131140

141+
/// The alignment of the destinations in the navigation rail.
142+
final double? groupAlignment;
143+
132144
/// Widget to be displayed in the body slot at the smallest breakpoint.
133145
///
134146
/// If nothing is entered for this property, then the default [body] is
@@ -246,6 +258,9 @@ class AdaptiveScaffold extends StatefulWidget {
246258
/// [Breakpoint].
247259
final double extendedNavigationRailWidth;
248260

261+
/// Used to map NavigationDestination to NavigationRailDestination.
262+
final NavigationRailDestinationBuilder? navigationRailDestinationBuilder;
263+
249264
/// Callback function for when the index of a [NavigationRail] changes.
250265
static WidgetBuilder emptyBuilder = (_) => const SizedBox();
251266

@@ -267,6 +282,9 @@ class AdaptiveScaffold extends StatefulWidget {
267282
/// Takes in a [selectedIndex] property for the current selected item in
268283
/// the [NavigationRail] and [extended] for whether the [NavigationRail]
269284
/// is extended or not.
285+
///
286+
/// If [labelType] is null, then the default value is
287+
/// [NavigationRailLabelType.none].
270288
static Builder standardNavigationRail({
271289
required List<NavigationRailDestination> destinations,
272290
double width = 72,
@@ -282,7 +300,7 @@ class AdaptiveScaffold extends StatefulWidget {
282300
IconThemeData? unselectedIconTheme,
283301
TextStyle? selectedLabelTextStyle,
284302
TextStyle? unSelectedLabelTextStyle,
285-
NavigationRailLabelType labelType = NavigationRailLabelType.none,
303+
NavigationRailLabelType? labelType = NavigationRailLabelType.none,
286304
}) {
287305
if (extended && width == 72) {
288306
width = 192;
@@ -513,6 +531,13 @@ class _AdaptiveScaffoldState extends State<AdaptiveScaffold> {
513531
final NavigationRailThemeData navRailTheme =
514532
Theme.of(context).navigationRailTheme;
515533

534+
final List<NavigationRailDestination> destinations = widget.destinations
535+
.map((NavigationDestination destination) =>
536+
widget.navigationRailDestinationBuilder
537+
?.call(widget.destinations.indexOf(destination), destination) ??
538+
AdaptiveScaffold.toRailDestination(destination))
539+
.toList();
540+
516541
return Scaffold(
517542
key: _scaffoldKey,
518543
appBar: widget.drawerBreakpoint.isActive(context) && widget.useDrawer ||
@@ -526,11 +551,15 @@ class _AdaptiveScaffoldState extends State<AdaptiveScaffold> {
526551
leading: widget.leadingExtendedNavRail,
527552
trailing: widget.trailingNavRail,
528553
selectedIndex: widget.selectedIndex,
529-
destinations: widget.destinations
530-
.map((NavigationDestination destination) =>
531-
AdaptiveScaffold.toRailDestination(destination))
532-
.toList(),
554+
destinations: destinations,
533555
onDestinationSelected: _onDrawerDestinationSelected,
556+
backgroundColor: navRailTheme.backgroundColor,
557+
selectedIconTheme: navRailTheme.selectedIconTheme,
558+
unselectedIconTheme: navRailTheme.unselectedIconTheme,
559+
selectedLabelTextStyle: navRailTheme.selectedLabelTextStyle,
560+
unselectedLabelTextStyle: navRailTheme.unselectedLabelTextStyle,
561+
groupAlignment: widget.groupAlignment,
562+
labelType: navRailTheme.labelType,
534563
),
535564
)
536565
: null,
@@ -548,16 +577,15 @@ class _AdaptiveScaffoldState extends State<AdaptiveScaffold> {
548577
leading: widget.leadingUnextendedNavRail,
549578
trailing: widget.trailingNavRail,
550579
selectedIndex: widget.selectedIndex,
551-
destinations: widget.destinations
552-
.map((NavigationDestination destination) =>
553-
AdaptiveScaffold.toRailDestination(destination))
554-
.toList(),
580+
destinations: destinations,
555581
onDestinationSelected: widget.onSelectedIndexChange,
556582
backgroundColor: navRailTheme.backgroundColor,
557583
selectedIconTheme: navRailTheme.selectedIconTheme,
558584
unselectedIconTheme: navRailTheme.unselectedIconTheme,
559585
selectedLabelTextStyle: navRailTheme.selectedLabelTextStyle,
560586
unSelectedLabelTextStyle: navRailTheme.unselectedLabelTextStyle,
587+
labelType: navRailTheme.labelType,
588+
groupAlignment: widget.groupAlignment,
561589
),
562590
),
563591
widget.largeBreakpoint: SlotLayout.from(
@@ -568,16 +596,15 @@ class _AdaptiveScaffoldState extends State<AdaptiveScaffold> {
568596
leading: widget.leadingExtendedNavRail,
569597
trailing: widget.trailingNavRail,
570598
selectedIndex: widget.selectedIndex,
571-
destinations: widget.destinations
572-
.map((NavigationDestination destination) =>
573-
AdaptiveScaffold.toRailDestination(destination))
574-
.toList(),
599+
destinations: destinations,
575600
onDestinationSelected: widget.onSelectedIndexChange,
576601
backgroundColor: navRailTheme.backgroundColor,
577602
selectedIconTheme: navRailTheme.selectedIconTheme,
578603
unselectedIconTheme: navRailTheme.unselectedIconTheme,
579604
selectedLabelTextStyle: navRailTheme.selectedLabelTextStyle,
580605
unSelectedLabelTextStyle: navRailTheme.unselectedLabelTextStyle,
606+
labelType: navRailTheme.labelType,
607+
groupAlignment: widget.groupAlignment,
581608
),
582609
),
583610
},

packages/flutter_adaptive_scaffold/pubspec.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: flutter_adaptive_scaffold
22
description: Widgets to easily build adaptive layouts, including navigation elements.
3-
version: 0.1.11+1
3+
version: 0.1.12
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+flutter_adaptive_scaffold%22
55
repository: https://github.com/flutter/packages/tree/main/packages/flutter_adaptive_scaffold
66

@@ -19,3 +19,4 @@ dev_dependencies:
1919
topics:
2020
- layout
2121
- ui
22+
- adaptive

packages/flutter_adaptive_scaffold/test/adaptive_scaffold_test.dart

Lines changed: 110 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -618,45 +618,45 @@ void main() {
618618
// creates a NavigationRail widget as expected with groupAlignment provided,
619619
// and checks whether the NavigationRail's groupAlignment matches the expected value.
620620
testWidgets(
621-
'groupAligment parameter of AdaptiveScaffold.standardNavigationRail works correctly',
622-
(WidgetTester tester) async {
623-
const List<NavigationRailDestination> destinations =
624-
<NavigationRailDestination>[
625-
NavigationRailDestination(
626-
icon: Icon(Icons.home),
627-
label: Text('Home'),
628-
),
629-
NavigationRailDestination(
630-
icon: Icon(Icons.account_circle),
631-
label: Text('Profile'),
632-
),
633-
NavigationRailDestination(
634-
icon: Icon(Icons.settings),
635-
label: Text('Settings'),
636-
),
637-
];
621+
'groupAligment parameter of AdaptiveScaffold.standardNavigationRail works correctly',
622+
(WidgetTester tester) async {
623+
const List<NavigationRailDestination> destinations =
624+
<NavigationRailDestination>[
625+
NavigationRailDestination(
626+
icon: Icon(Icons.home),
627+
label: Text('Home'),
628+
),
629+
NavigationRailDestination(
630+
icon: Icon(Icons.account_circle),
631+
label: Text('Profile'),
632+
),
633+
NavigationRailDestination(
634+
icon: Icon(Icons.settings),
635+
label: Text('Settings'),
636+
),
637+
];
638638

639-
// Align to bottom.
640-
const double groupAlignment = 1.0;
639+
const double groupAlignment = 1.0;
641640

642-
await tester.pumpWidget(
643-
MaterialApp(
644-
home: Scaffold(
645-
body: Builder(
646-
builder: (BuildContext context) {
647-
return AdaptiveScaffold.standardNavigationRail(
648-
destinations: destinations,
649-
groupAlignment: groupAlignment,
650-
);
651-
},
641+
await tester.pumpWidget(
642+
MaterialApp(
643+
home: Scaffold(
644+
body: Builder(
645+
builder: (BuildContext context) {
646+
return AdaptiveScaffold.standardNavigationRail(
647+
destinations: destinations,
648+
groupAlignment: groupAlignment,
649+
);
650+
},
651+
),
652652
),
653653
),
654-
),
655-
);
656-
final NavigationRail rail =
657-
tester.widget<NavigationRail>(find.byType(NavigationRail));
658-
expect(rail.groupAlignment, equals(groupAlignment));
659-
});
654+
);
655+
final NavigationRail rail =
656+
tester.widget<NavigationRail>(find.byType(NavigationRail));
657+
expect(rail.groupAlignment, equals(groupAlignment));
658+
},
659+
);
660660

661661
testWidgets(
662662
"doesn't override Directionality",
@@ -744,6 +744,81 @@ void main() {
744744
);
745745
},
746746
);
747+
748+
// Test for navigationRailDestinationBuilder parameter.
749+
testWidgets('adaptive scaffold custom navigation rail destination mapping',
750+
(WidgetTester tester) async {
751+
const List<NavigationDestination> destinations = <NavigationDestination>[
752+
NavigationDestination(
753+
icon: Icon(Icons.home),
754+
label: 'Home',
755+
),
756+
NavigationDestination(
757+
icon: Icon(Icons.account_circle),
758+
label: 'Profile',
759+
),
760+
];
761+
762+
NavigationRailDestination customMapping(
763+
int index, NavigationDestination destination) {
764+
return NavigationRailDestination(
765+
icon: destination.icon,
766+
label: Text('Custom ${destination.label}'),
767+
);
768+
}
769+
770+
await tester.pumpWidget(
771+
MaterialApp(
772+
home: MediaQuery(
773+
data: const MediaQueryData(size: Size(800, 600)),
774+
child: AdaptiveScaffold(
775+
destinations: destinations,
776+
navigationRailDestinationBuilder: customMapping,
777+
),
778+
),
779+
),
780+
);
781+
782+
expect(find.text('Custom Home'), findsOneWidget);
783+
expect(find.text('Custom Profile'), findsOneWidget);
784+
});
785+
786+
// Test for labelType setting through the navigation rail theme.
787+
testWidgets(
788+
'adaptive scaffold respects NavigationRailLabelType from theme',
789+
(WidgetTester tester) async {
790+
const List<NavigationDestination> destinations = <NavigationDestination>[
791+
NavigationDestination(
792+
icon: Icon(Icons.home),
793+
label: 'Home',
794+
),
795+
NavigationDestination(
796+
icon: Icon(Icons.account_circle),
797+
label: 'Profile',
798+
),
799+
];
800+
801+
await tester.pumpWidget(
802+
MaterialApp(
803+
theme: ThemeData(
804+
navigationRailTheme: const NavigationRailThemeData(
805+
labelType: NavigationRailLabelType.all,
806+
),
807+
),
808+
home: MediaQuery(
809+
data: const MediaQueryData(size: Size(800, 600)),
810+
child: AdaptiveScaffold(
811+
destinations: destinations,
812+
),
813+
),
814+
),
815+
);
816+
817+
final NavigationRail rail =
818+
tester.widget<NavigationRail>(find.byType(NavigationRail));
819+
expect(rail.labelType, NavigationRailLabelType.all);
820+
},
821+
);
747822
}
748823

749824
/// An empty widget that implements [PreferredSizeWidget] to ensure that

0 commit comments

Comments
 (0)