Unverified Commit d803f02d authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Add activeIcon property to BottomNavigationBarItem (#18125)

parent 0891a113
...@@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; ...@@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
class NavigationIconView { class NavigationIconView {
NavigationIconView({ NavigationIconView({
Widget icon, Widget icon,
Widget activeIcon,
String title, String title,
Color color, Color color,
TickerProvider vsync, TickerProvider vsync,
...@@ -15,6 +16,7 @@ class NavigationIconView { ...@@ -15,6 +16,7 @@ class NavigationIconView {
_title = title, _title = title,
item = new BottomNavigationBarItem( item = new BottomNavigationBarItem(
icon: icon, icon: icon,
activeIcon: activeIcon,
title: new Text(title), title: new Text(title),
backgroundColor: color, backgroundColor: color,
), ),
...@@ -81,6 +83,21 @@ class CustomIcon extends StatelessWidget { ...@@ -81,6 +83,21 @@ class CustomIcon extends StatelessWidget {
} }
} }
class CustomInactiveIcon extends StatelessWidget {
@override
Widget build(BuildContext context) {
final IconThemeData iconTheme = IconTheme.of(context);
return new Container(
margin: const EdgeInsets.all(4.0),
width: iconTheme.size - 8.0,
height: iconTheme.size - 8.0,
decoration: new BoxDecoration(
border: new Border.all(color: iconTheme.color, width: 2.0),
)
);
}
}
class BottomNavigationDemo extends StatefulWidget { class BottomNavigationDemo extends StatefulWidget {
static const String routeName = '/material/bottom_navigation'; static const String routeName = '/material/bottom_navigation';
...@@ -105,19 +122,22 @@ class _BottomNavigationDemoState extends State<BottomNavigationDemo> ...@@ -105,19 +122,22 @@ class _BottomNavigationDemoState extends State<BottomNavigationDemo>
vsync: this, vsync: this,
), ),
new NavigationIconView( new NavigationIconView(
icon: new CustomIcon(), activeIcon: new CustomIcon(),
icon: new CustomInactiveIcon(),
title: 'Box', title: 'Box',
color: Colors.deepOrange, color: Colors.deepOrange,
vsync: this, vsync: this,
), ),
new NavigationIconView( new NavigationIconView(
icon: const Icon(Icons.cloud), activeIcon: const Icon(Icons.cloud),
icon: const Icon(Icons.cloud_queue),
title: 'Cloud', title: 'Cloud',
color: Colors.teal, color: Colors.teal,
vsync: this, vsync: this,
), ),
new NavigationIconView( new NavigationIconView(
icon: const Icon(Icons.favorite), activeIcon: const Icon(Icons.favorite),
icon: const Icon(Icons.favorite_border),
title: 'Favorites', title: 'Favorites',
color: Colors.indigo, color: Colors.indigo,
vsync: this, vsync: this,
......
...@@ -189,7 +189,7 @@ class _BottomNavigationTile extends StatelessWidget { ...@@ -189,7 +189,7 @@ class _BottomNavigationTile extends StatelessWidget {
color: iconColor, color: iconColor,
size: iconSize, size: iconSize,
), ),
child: item.icon, child: selected ? item.activeIcon : item.icon,
), ),
), ),
); );
......
...@@ -25,8 +25,10 @@ class BottomNavigationBarItem { ...@@ -25,8 +25,10 @@ class BottomNavigationBarItem {
const BottomNavigationBarItem({ const BottomNavigationBarItem({
@required this.icon, @required this.icon,
@required this.title, @required this.title,
Widget activeIcon,
this.backgroundColor, this.backgroundColor,
}) : assert(icon != null), }) : this.activeIcon = activeIcon ?? icon,
assert(icon != null),
assert(title != null); assert(title != null);
/// The icon of the item. /// The icon of the item.
...@@ -34,8 +36,31 @@ class BottomNavigationBarItem { ...@@ -34,8 +36,31 @@ class BottomNavigationBarItem {
/// Typically the icon is an [Icon] or an [ImageIcon] widget. If another type /// Typically the icon is an [Icon] or an [ImageIcon] widget. If another type
/// of widget is provided then it should configure itself to match the current /// of widget is provided then it should configure itself to match the current
/// [IconTheme] size and color. /// [IconTheme] size and color.
///
/// If [activeIcon] is provided, this will only be displayed when the item is
/// not selected.
///
/// To make the bottom navigation bar more accessible, consider choosing an
/// icon with a stroked and filled version, such as [Icons.cloud] and
/// [Icons.cloud_queue]. [icon] should be set to the stroked version and
/// [activeIcon] to the filled version.
///
/// If a particular icon doesn't have a stroked or filled version, then don't
/// pair unrelated icons. Instead, make sure to use a
/// [BottomNavigationBarType.shifting].
final Widget icon; final Widget icon;
/// An alternative icon displayed when this bottom navigation item is
/// selected.
///
/// If this icon is not provided, the bottom navigation bar will display
/// [icon] in either state.
///
/// See also:
///
/// * [BottomNavigationBarItem.icon], for a description of how to pair icons.
final Widget activeIcon;
/// The title of the item. /// The title of the item.
final Widget title; final Widget title;
......
...@@ -486,6 +486,59 @@ void main() { ...@@ -486,6 +486,59 @@ void main() {
expect(box, paints..circle(x: 600.0)..circle(x: 200.0)..circle(x: 600.0)); expect(box, paints..circle(x: 600.0)..circle(x: 200.0)..circle(x: 600.0));
}); });
testWidgets('BottomNavigationBar inactiveIcon shown', (WidgetTester tester) async {
const Key filled = const Key('filled');
const Key stroked = const Key('stroked');
int selectedItem = 0;
await tester.pumpWidget(
boilerplate(
textDirection: TextDirection.ltr,
bottomNavigationBar: new BottomNavigationBar(
currentIndex: selectedItem,
items: const <BottomNavigationBarItem>[
const BottomNavigationBarItem(
activeIcon: const Icon(Icons.favorite, key: filled),
icon: const Icon(Icons.favorite_border, key: stroked),
title: const Text('Favorite'),
),
const BottomNavigationBarItem(
icon: const Icon(Icons.access_alarm),
title: const Text('Alarm'),
),
],
),
),
);
expect(find.byKey(filled), findsOneWidget);
expect(find.byKey(stroked), findsNothing);
selectedItem = 1;
await tester.pumpWidget(
boilerplate(
textDirection: TextDirection.ltr,
bottomNavigationBar: new BottomNavigationBar(
currentIndex: selectedItem,
items: const <BottomNavigationBarItem>[
const BottomNavigationBarItem(
activeIcon: const Icon(Icons.favorite, key: filled),
icon: const Icon(Icons.favorite_border, key: stroked),
title: const Text('Favorite'),
),
const BottomNavigationBarItem(
icon: const Icon(Icons.access_alarm),
title: const Text('Alarm'),
),
],
),
),
);
expect(find.byKey(filled), findsNothing);
expect(find.byKey(stroked), findsOneWidget);
});
testWidgets('BottomNavigationBar semantics', (WidgetTester tester) async { testWidgets('BottomNavigationBar semantics', (WidgetTester tester) async {
final SemanticsTester semantics = new SemanticsTester(tester); final SemanticsTester semantics = new SemanticsTester(tester);
......
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