Skip to content

Commit

Permalink
nav drawer (#115668)
Browse files Browse the repository at this point in the history
  • Loading branch information
hannah-hyj authored Nov 18, 2022
1 parent 01c1e8e commit 0e57147
Show file tree
Hide file tree
Showing 14 changed files with 1,711 additions and 34 deletions.
4 changes: 4 additions & 0 deletions dev/tools/gen_defaults/bin/gen_defaults.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ import 'package:gen_defaults/checkbox_template.dart';
import 'package:gen_defaults/color_scheme_template.dart';
import 'package:gen_defaults/dialog_template.dart';
import 'package:gen_defaults/divider_template.dart';
import 'package:gen_defaults/drawer_template.dart';
import 'package:gen_defaults/fab_template.dart';
import 'package:gen_defaults/filter_chip_template.dart';
import 'package:gen_defaults/icon_button_template.dart';
import 'package:gen_defaults/input_chip_template.dart';
import 'package:gen_defaults/input_decorator_template.dart';
import 'package:gen_defaults/menu_template.dart';
import 'package:gen_defaults/navigation_bar_template.dart';
import 'package:gen_defaults/navigation_drawer_template.dart';
import 'package:gen_defaults/navigation_rail_template.dart';
import 'package:gen_defaults/popup_menu_template.dart';
import 'package:gen_defaults/progress_indicator_template.dart';
Expand Down Expand Up @@ -144,6 +146,7 @@ Future<void> main(List<String> args) async {
DialogFullscreenTemplate('DialogFullscreen', '$materialLib/dialog.dart', tokens).updateFile();
DialogTemplate('Dialog', '$materialLib/dialog.dart', tokens).updateFile();
DividerTemplate('Divider', '$materialLib/divider.dart', tokens).updateFile();
DrawerTemplate('Drawer', '$materialLib/drawer.dart', tokens).updateFile();
FABTemplate('FAB', '$materialLib/floating_action_button.dart', tokens).updateFile();
FilterChipTemplate('ChoiceChip', '$materialLib/choice_chip.dart', tokens).updateFile();
FilterChipTemplate('FilterChip', '$materialLib/filter_chip.dart', tokens).updateFile();
Expand All @@ -152,6 +155,7 @@ Future<void> main(List<String> args) async {
InputDecoratorTemplate('InputDecorator', '$materialLib/input_decorator.dart', tokens).updateFile();
MenuTemplate('Menu', '$materialLib/menu_anchor.dart', tokens).updateFile();
NavigationBarTemplate('NavigationBar', '$materialLib/navigation_bar.dart', tokens).updateFile();
NavigationDrawerTemplate('NavigationDrawer', '$materialLib/navigation_drawer.dart', tokens).updateFile();
NavigationRailTemplate('NavigationRail', '$materialLib/navigation_rail.dart', tokens).updateFile();
PopupMenuTemplate('PopupMenu', '$materialLib/popup_menu.dart', tokens).updateFile();
ProgressIndicatorTemplate('ProgressIndicator', '$materialLib/progress_indicator.dart', tokens).updateFile();
Expand Down
42 changes: 42 additions & 0 deletions dev/tools/gen_defaults/lib/drawer_template.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'template.dart';

class DrawerTemplate extends TokenTemplate {
const DrawerTemplate(super.blockName, super.fileName, super.tokens);

@override
String generate() => '''
class _${blockName}DefaultsM3 extends DrawerThemeData {
const _${blockName}DefaultsM3(this.context)
: super(elevation: ${elevation("md.comp.navigation-drawer.modal.container")});
final BuildContext context;
@override
Color? get backgroundColor => ${componentColor("md.comp.navigation-drawer.container")};
@override
Color? get surfaceTintColor => ${colorOrTransparent("md.comp.navigation-drawer.container.surface-tint-layer.color")};
@override
Color? get shadowColor => ${colorOrTransparent("md.comp.navigation-drawer.container.shadow-color")};
// This don't appear to be tokens for this value, but it is
// shown in the spec.
@override
ShapeBorder? get shape => const RoundedRectangleBorder(
borderRadius: BorderRadius.horizontal(right: Radius.circular(16.0)),
);
// This don't appear to be tokens for this value, but it is
// shown in the spec.
@override
ShapeBorder? get endShape => const RoundedRectangleBorder(
borderRadius: BorderRadius.horizontal(left: Radius.circular(16.0)),
);
}
''';
}
60 changes: 60 additions & 0 deletions dev/tools/gen_defaults/lib/navigation_drawer_template.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'template.dart';

class NavigationDrawerTemplate extends TokenTemplate {
const NavigationDrawerTemplate(super.blockName, super.fileName, super.tokens);

@override
String generate() => '''
class _${blockName}DefaultsM3 extends NavigationDrawerThemeData {
const _${blockName}DefaultsM3(this.context)
: super(
elevation: ${elevation("md.comp.navigation-drawer.modal.container")},
tileHeight: ${tokens["md.comp.navigation-drawer.active-indicator.height"]},
indicatorShape: ${shape("md.comp.navigation-drawer.active-indicator")},
indicatorSize: const Size(${tokens["md.comp.navigation-drawer.active-indicator.width"]}, ${tokens["md.comp.navigation-drawer.active-indicator.height"]}),
);
final BuildContext context;
@override
Color? get backgroundColor => ${componentColor("md.comp.navigation-drawer.container")};
@override
Color? get surfaceTintColor => ${colorOrTransparent("md.comp.navigation-drawer.container.surface-tint-layer.color")};
@override
Color? get shadowColor => ${colorOrTransparent("md.comp.navigation-drawer.container.shadow-color")};
@override
Color? get indicatorColor => ${componentColor("md.comp.navigation-drawer.active-indicator")};
@override
MaterialStateProperty<IconThemeData?>? get iconTheme {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
return IconThemeData(
size: ${tokens["md.comp.navigation-drawer.icon.size"]},
color: states.contains(MaterialState.selected)
? ${componentColor("md.comp.navigation-drawer.active.icon.")}
: ${componentColor("md.comp.navigation-drawer.inactive.icon")},
);
});
}
@override
MaterialStateProperty<TextStyle?>? get labelTextStyle {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
final TextStyle style = ${textStyle("md.comp.navigation-drawer.label-text")}!;
return style.apply(
color: states.contains(MaterialState.selected)
? ${componentColor("md.comp.navigation-drawer.active.label-text")}
: ${componentColor("md.comp.navigation-drawer.inactive.label-text")},
);
});
}
}
''';
}
178 changes: 178 additions & 0 deletions examples/api/lib/material/navigation_drawer/navigation_drawer.0.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Flutter code sample for [NavigationDrawer] .

// Builds an adaptive navigation widget layout. When the screen width is less than
// 450, A [NavigationBar] will be displayed. Otherwise, a [NavigationRail] will be
// displayed on the left side, and also a button to open the [NavigationDrawer].
// All of these navigation widgets are built from an indentical list of data.

import 'package:flutter/material.dart';

class ExampleDestination {
const ExampleDestination(this.label, this.icon, this.selectedIcon);

final String label;
final Widget icon;
final Widget selectedIcon;
}

const List<ExampleDestination> destinations = <ExampleDestination>[
ExampleDestination('page 0', Icon(Icons.widgets_outlined), Icon(Icons.widgets)),
ExampleDestination('page 1', Icon(Icons.format_paint_outlined), Icon(Icons.format_paint)),
ExampleDestination('page 2', Icon(Icons.text_snippet_outlined), Icon(Icons.text_snippet)),
ExampleDestination('page 3', Icon(Icons.invert_colors_on_outlined), Icon(Icons.opacity)),
];

void main() {
runApp(
MaterialApp(
title: 'NavigationDrawer Example',
debugShowCheckedModeBanner: false,
theme: ThemeData(useMaterial3: true),
home: const NavigationDrawerExample(),
),
);
}

class NavigationDrawerExample extends StatefulWidget {
const NavigationDrawerExample({super.key});

@override
State<NavigationDrawerExample> createState() => _NavigationDrawerExampleState();
}

class _NavigationDrawerExampleState extends State<NavigationDrawerExample> {
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();

int screenIndex = 0;
late bool showNavigationDrawer;

void handleScreenChanged(int selectedScreen) {
setState(() {
screenIndex = selectedScreen;
});
}

void openDrawer() {
scaffoldKey.currentState!.openEndDrawer();
}

Widget buildBottomBarScaffold(){
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text('Page Index = $screenIndex'),
],
),
),
bottomNavigationBar: NavigationBar(
selectedIndex: screenIndex,
onDestinationSelected: (int index) {
setState(() {
screenIndex = index;
});
},
destinations: destinations
.map((ExampleDestination destination) {
return NavigationDestination(
label: destination.label,
icon: destination.icon,
selectedIcon: destination.selectedIcon,
tooltip: destination.label,
);
})
.toList(),
),
);
}

Widget buildDrawerScaffold(BuildContext context){
return Scaffold(
key: scaffoldKey,
body: SafeArea(
bottom: false,
top: false,
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 5),
child: NavigationRail(
minWidth: 50,
destinations: destinations
.map((ExampleDestination destination) {
return NavigationRailDestination(
label: Text(destination.label),
icon: destination.icon,
selectedIcon: destination.selectedIcon,
);
})
.toList(),
selectedIndex: screenIndex,
useIndicator: true,
onDestinationSelected: (int index) {
setState(() {
screenIndex = index;
});
},
),
),
const VerticalDivider(thickness: 1, width: 1),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text('Page Index = $screenIndex'),
ElevatedButton(
onPressed: openDrawer,
child: const Text('Open Drawer'),
),
],
),
),
],
),
),
endDrawer: NavigationDrawer(
onDestinationSelected: handleScreenChanged,
selectedIndex: screenIndex,
children: <Widget>[
Padding(
padding: const EdgeInsets.fromLTRB(28, 16, 16, 10),
child: Text(
'Header',
style: Theme.of(context).textTheme.titleSmall,
),
),
...destinations
.map((ExampleDestination destination) {
return NavigationDrawerDestination(
label: Text(destination.label),
icon: destination.icon,
selectedIcon: destination.selectedIcon,
);
}),
const Padding(
padding: EdgeInsets.fromLTRB(28, 16, 28, 10),
child: Divider(),
),
],
),
);
}

@override
void didChangeDependencies() {
super.didChangeDependencies();
showNavigationDrawer = MediaQuery.of(context).size.width >= 450;
}

@override
Widget build(BuildContext context) {
return showNavigationDrawer ? buildDrawerScaffold(context) : buildBottomBarScaffold();
}
}
2 changes: 2 additions & 0 deletions packages/flutter/lib/material.dart
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ export 'src/material/menu_theme.dart';
export 'src/material/mergeable_material.dart';
export 'src/material/navigation_bar.dart';
export 'src/material/navigation_bar_theme.dart';
export 'src/material/navigation_drawer.dart';
export 'src/material/navigation_drawer_theme.dart';
export 'src/material/navigation_rail.dart';
export 'src/material/navigation_rail_theme.dart';
export 'src/material/no_splash.dart';
Expand Down
Loading

0 comments on commit 0e57147

Please sign in to comment.