Unverified Commit eca09252 authored by Taha Tesser's avatar Taha Tesser Committed by GitHub

Add Material 3 `NavigationRail` example and improve Material 2 example (#101345)

parent 3c4d7a1a
......@@ -11,26 +11,27 @@ void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
home: NavRailExample(),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
class NavRailExample extends StatefulWidget {
const NavRailExample({Key? key}) : super(key: key);
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
State<NavRailExample> createState() => _NavRailExampleState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
class _NavRailExampleState extends State<NavRailExample> {
int _selectedIndex = 0;
NavigationRailLabelType labelType = NavigationRailLabelType.all;
bool showLeading = false;
bool showTrailing = false;
double groupAligment = -1.0;
@override
Widget build(BuildContext context) {
......@@ -39,12 +40,26 @@ class _MyStatefulWidgetState extends State<MyStatefulWidget> {
children: <Widget>[
NavigationRail(
selectedIndex: _selectedIndex,
groupAlignment: groupAligment,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
labelType: NavigationRailLabelType.selected,
labelType: labelType,
leading: showLeading ? FloatingActionButton(
elevation: 0,
onPressed: () {
// Add your onPressed code here!
},
child: const Icon(Icons.add),
) : const SizedBox(),
trailing: showTrailing ? IconButton(
onPressed: () {
// Add your onPressed code here!
},
icon: const Icon(Icons.more_horiz_rounded),
) : const SizedBox(),
destinations: const <NavigationRailDestination>[
NavigationRailDestination(
icon: Icon(Icons.favorite_border),
......@@ -65,11 +80,100 @@ class _MyStatefulWidgetState extends State<MyStatefulWidget> {
),
const VerticalDivider(thickness: 1, width: 1),
// This is the main content.
Expanded(
child: Center(
child: Text('selectedIndex: $_selectedIndex'),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('selectedIndex: $_selectedIndex'),
const SizedBox(height: 20),
Text('Label type: ${labelType.name}'),
const SizedBox(height: 10),
OverflowBar(
spacing: 10.0,
children: <Widget>[
ElevatedButton(
onPressed: () {
setState(() {
labelType = NavigationRailLabelType.none;
});
},
child: const Text('None'),
),
ElevatedButton(
onPressed: () {
setState(() {
labelType = NavigationRailLabelType.selected;
});
},
child: const Text('Selected'),
),
ElevatedButton(
onPressed: () {
setState(() {
labelType = NavigationRailLabelType.all;
});
},
child: const Text('All'),
),
],
),
const SizedBox(height: 20),
Text('Group alignment: $groupAligment'),
const SizedBox(height: 10),
OverflowBar(
spacing: 10.0,
children: <Widget>[
ElevatedButton(
onPressed: () {
setState(() {
groupAligment = -1.0;
});
},
child: const Text('Top'),
),
ElevatedButton(
onPressed: () {
setState(() {
groupAligment = 0.0;
});
},
child: const Text('Center'),
),
ElevatedButton(
onPressed: () {
setState(() {
groupAligment = 1.0;
});
},
child: const Text('Bottom'),
),
],
),
const SizedBox(height: 20),
OverflowBar(
spacing: 10.0,
children: <Widget>[
ElevatedButton(
onPressed: () {
setState(() {
showLeading = !showLeading;
});
},
child: Text(showLeading ? 'Hide Leading' : 'Show Leading'),
),
ElevatedButton(
onPressed: () {
setState(() {
showTrailing = !showTrailing;
});
},
child: Text(showTrailing ? 'Hide Trailing' : 'Show Trailing'),
),
],
),
],
),
),
)
],
),
);
......
// 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 NavigationRail
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(colorSchemeSeed: const Color(0xff6750a4), useMaterial3: true),
home: const NavRailExample(),
);
}
}
class NavRailExample extends StatefulWidget {
const NavRailExample({Key? key}) : super(key: key);
@override
State<NavRailExample> createState() => _NavRailExampleState();
}
class _NavRailExampleState extends State<NavRailExample> {
int _selectedIndex = 0;
NavigationRailLabelType labelType = NavigationRailLabelType.all;
bool showLeading = false;
bool showTrailing = false;
double groupAligment = -1.0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Row(
children: <Widget>[
NavigationRail(
selectedIndex: _selectedIndex,
groupAlignment: groupAligment,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
labelType: labelType,
leading: showLeading ? FloatingActionButton(
elevation: 0,
onPressed: () {
// Add your onPressed code here!
},
child: const Icon(Icons.add),
) : const SizedBox(),
trailing: showTrailing ? IconButton(
onPressed: () {
// Add your onPressed code here!
},
icon: const Icon(Icons.more_horiz_rounded),
) : const SizedBox(),
destinations: const <NavigationRailDestination>[
NavigationRailDestination(
icon: Icon(Icons.favorite_border),
selectedIcon: Icon(Icons.favorite),
label: Text('First'),
),
NavigationRailDestination(
icon: Icon(Icons.bookmark_border),
selectedIcon: Icon(Icons.book),
label: Text('Second'),
),
NavigationRailDestination(
icon: Icon(Icons.star_border),
selectedIcon: Icon(Icons.star),
label: Text('Third'),
),
],
),
const VerticalDivider(thickness: 1, width: 1),
// This is the main content.
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('selectedIndex: $_selectedIndex'),
const SizedBox(height: 20),
Text('Label type: ${labelType.name}'),
const SizedBox(height: 10),
OverflowBar(
spacing: 10.0,
children: <Widget>[
ElevatedButton(
onPressed: () {
setState(() {
labelType = NavigationRailLabelType.none;
});
},
child: const Text('None'),
),
ElevatedButton(
onPressed: () {
setState(() {
labelType = NavigationRailLabelType.selected;
});
},
child: const Text('Selected'),
),
ElevatedButton(
onPressed: () {
setState(() {
labelType = NavigationRailLabelType.all;
});
},
child: const Text('All'),
),
],
),
const SizedBox(height: 20),
Text('Group alignment: $groupAligment'),
const SizedBox(height: 10),
OverflowBar(
spacing: 10.0,
children: <Widget>[
ElevatedButton(
onPressed: () {
setState(() {
groupAligment = -1.0;
});
},
child: const Text('Top'),
),
ElevatedButton(
onPressed: () {
setState(() {
groupAligment = 0.0;
});
},
child: const Text('Center'),
),
ElevatedButton(
onPressed: () {
setState(() {
groupAligment = 1.0;
});
},
child: const Text('Bottom'),
),
],
),
const SizedBox(height: 20),
OverflowBar(
spacing: 10.0,
children: <Widget>[
ElevatedButton(
onPressed: () {
setState(() {
showLeading = !showLeading;
});
},
child: Text(showLeading ? 'Hide Leading' : 'Show Leading'),
),
ElevatedButton(
onPressed: () {
setState(() {
showTrailing = !showTrailing;
});
},
child: Text(showTrailing ? 'Hide Trailing' : 'Show Trailing'),
),
],
),
],
),
),
],
),
),
);
}
}
......@@ -13,15 +13,11 @@ void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'NavigationRail.extendedAnimation Sample';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
return const MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyNavigationRail(),
body: MyNavigationRail(),
),
);
}
......@@ -78,7 +74,14 @@ class _MyNavigationRailState extends State<MyNavigationRail> {
// This is the main content.
Expanded(
child: Center(
child: Text('selectedIndex: $_selectedIndex'),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Tap on FloatingActionButton to expand'),
const SizedBox(height: 20),
Text('selectedIndex: $_selectedIndex'),
],
),
),
)
],
......
// 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 'package:flutter/material.dart';
import 'package:flutter_api_samples/material/navigation_rail/navigation_rail.0.dart'
as example;
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Navigation rail updates destination on tap',
(WidgetTester tester) async {
await tester.pumpWidget(
const example.MyApp(),
);
final NavigationRail navigationRailWidget =
tester.firstWidget(find.byType(NavigationRail));
/// NavigationRailDestinations must be rendered
expect(find.text('First'), findsOneWidget);
expect(find.text('Second'), findsOneWidget);
expect(find.text('Third'), findsOneWidget);
/// initial index must be zero
expect(navigationRailWidget.selectedIndex, 0);
/// switch to second tab
await tester.tap(find.text('Second'));
await tester.pumpAndSettle();
expect(find.text('selectedIndex: 1'), findsOneWidget);
/// switch to third tab
await tester.tap(find.text('Third'));
await tester.pumpAndSettle();
expect(find.text('selectedIndex: 2'), findsOneWidget);
});
testWidgets('Navigation rail updates label type', (WidgetTester tester) async {
await tester.pumpWidget(
const example.MyApp(),
);
// initial label type set to all.
expect(find.text('Label type: all'), findsOneWidget);
// switch to selected label type
await tester.tap(find.widgetWithText(ElevatedButton, 'Selected'));
await tester.pumpAndSettle();
expect(find.text('Label type: selected'), findsOneWidget);
// switch to none label type
await tester.tap(find.widgetWithText(ElevatedButton, 'None'));
await tester.pumpAndSettle();
expect(find.text('Label type: none'), findsOneWidget);
});
testWidgets('Navigation rail updates group alignment', (WidgetTester tester) async {
await tester.pumpWidget(
const example.MyApp(),
);
// initial group alignment set top top.
expect(find.text('Group alignment: -1.0'), findsOneWidget);
// switch to center alignment
await tester.tap(find.widgetWithText(ElevatedButton, 'Center'));
await tester.pumpAndSettle();
expect(find.text('Group alignment: 0.0'), findsOneWidget);
// switch to bottom alignment
await tester.tap(find.widgetWithText(ElevatedButton, 'Bottom'));
await tester.pumpAndSettle();
expect(find.text('Group alignment: 1.0'), findsOneWidget);
});
testWidgets('Navigation rail shows leading/trailing widgets', (WidgetTester tester) async {
await tester.pumpWidget(
const example.MyApp(),
);
// Initially leading/trailing widgets are hidden.
expect(find.byType(FloatingActionButton), findsNothing);
expect(find.byType(IconButton), findsNothing);
// Tap to show leading Widget.
await tester.tap(find.widgetWithText(ElevatedButton, 'Show Leading'));
await tester.pumpAndSettle();
expect(find.byType(FloatingActionButton), findsOneWidget);
expect(find.byType(IconButton), findsNothing);
// Tap to show trailing Widget.
await tester.tap(find.widgetWithText(ElevatedButton, 'Show Trailing'));
await tester.pumpAndSettle();
expect(find.byType(FloatingActionButton), findsOneWidget);
expect(find.byType(IconButton), findsOneWidget);
});
}
// 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 'package:flutter/material.dart';
import 'package:flutter_api_samples/material/navigation_rail/navigation_rail.1.dart'
as example;
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Navigation rail updates destination on tap',
(WidgetTester tester) async {
await tester.pumpWidget(
const example.MyApp(),
);
final NavigationRail navigationRailWidget =
tester.firstWidget(find.byType(NavigationRail));
/// NavigationRailDestinations must be rendered
expect(find.text('First'), findsOneWidget);
expect(find.text('Second'), findsOneWidget);
expect(find.text('Third'), findsOneWidget);
/// initial index must be zero
expect(navigationRailWidget.selectedIndex, 0);
/// switch to second tab
await tester.tap(find.text('Second'));
await tester.pumpAndSettle();
expect(find.text('selectedIndex: 1'), findsOneWidget);
/// switch to third tab
await tester.tap(find.text('Third'));
await tester.pumpAndSettle();
expect(find.text('selectedIndex: 2'), findsOneWidget);
});
testWidgets('Navigation rail updates label type', (WidgetTester tester) async {
await tester.pumpWidget(
const example.MyApp(),
);
// initial label type set to all.
expect(find.text('Label type: all'), findsOneWidget);
// switch to selected label type
await tester.tap(find.widgetWithText(ElevatedButton, 'Selected'));
await tester.pumpAndSettle();
expect(find.text('Label type: selected'), findsOneWidget);
// switch to none label type
await tester.tap(find.widgetWithText(ElevatedButton, 'None'));
await tester.pumpAndSettle();
expect(find.text('Label type: none'), findsOneWidget);
});
testWidgets('Navigation rail updates group alignment', (WidgetTester tester) async {
await tester.pumpWidget(
const example.MyApp(),
);
// initial group alignment set top top.
expect(find.text('Group alignment: -1.0'), findsOneWidget);
// switch to center alignment
await tester.tap(find.widgetWithText(ElevatedButton, 'Center'));
await tester.pumpAndSettle();
expect(find.text('Group alignment: 0.0'), findsOneWidget);
// switch to bottom alignment
await tester.tap(find.widgetWithText(ElevatedButton, 'Bottom'));
await tester.pumpAndSettle();
expect(find.text('Group alignment: 1.0'), findsOneWidget);
});
testWidgets('Navigation rail shows leading/trailing widgets', (WidgetTester tester) async {
await tester.pumpWidget(
const example.MyApp(),
);
// Initially leading/trailing widgets are hidden.
expect(find.byType(FloatingActionButton), findsNothing);
expect(find.byType(IconButton), findsNothing);
// Tap to show leading Widget.
await tester.tap(find.widgetWithText(ElevatedButton, 'Show Leading'));
await tester.pumpAndSettle();
expect(find.byType(FloatingActionButton), findsOneWidget);
expect(find.byType(IconButton), findsNothing);
// Tap to show trailing Widget.
await tester.tap(find.widgetWithText(ElevatedButton, 'Show Trailing'));
await tester.pumpAndSettle();
expect(find.byType(FloatingActionButton), findsOneWidget);
expect(find.byType(IconButton), findsOneWidget);
});
}
......@@ -46,6 +46,13 @@ import 'theme.dart';
/// ** See code in examples/api/lib/material/navigation_rail/navigation_rail.0.dart **
/// {@end-tool}
///
/// {@tool dartpad}
/// This sample shows the creation of [NavigationRail] widget used within a Scaffold with 3
/// [NavigationRailDestination]s, as described in: https://m3.material.io/components/navigation-rail/overview
///
/// ** See code in examples/api/lib/material/navigation_rail/navigation_rail.1.dart **
/// {@end-tool}
///
/// See also:
///
/// * [Scaffold], which can display the navigation rail within a [Row] of the
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment