Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
617ca627
Unverified
Commit
617ca627
authored
Feb 22, 2019
by
Hans Muller
Committed by
GitHub
Feb 22, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Material] Expand BottomNavigationBar API (reprise) (#28159)
parent
b96ae03b
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
856 additions
and
208 deletions
+856
-208
bottom_navigation_demo.dart
...ter_gallery/lib/demo/material/bottom_navigation_demo.dart
+1
-0
bottom_navigation_bar.dart
packages/flutter/lib/src/material/bottom_navigation_bar.dart
+327
-202
bottom_navigation_bar_item.dart
...s/flutter/lib/src/widgets/bottom_navigation_bar_item.dart
+3
-3
bottom_navigation_bar_test.dart
...ges/flutter/test/material/bottom_navigation_bar_test.dart
+525
-3
No files found.
examples/flutter_gallery/lib/demo/material/bottom_navigation_demo.dart
View file @
617ca627
...
...
@@ -189,6 +189,7 @@ class _BottomNavigationDemoState extends State<BottomNavigationDemo>
.
toList
(),
currentIndex:
_currentIndex
,
type:
_type
,
//iconSize: 4.0,
onTap:
(
int
index
)
{
setState
(()
{
_navigationViews
[
_currentIndex
].
controller
.
reverse
();
...
...
packages/flutter/lib/src/material/bottom_navigation_bar.dart
View file @
617ca627
...
...
@@ -17,11 +17,6 @@ import 'material_localizations.dart';
import
'text_theme.dart'
;
import
'theme.dart'
;
const
double
_kActiveFontSize
=
14.0
;
const
double
_kInactiveFontSize
=
12.0
;
const
double
_kTopMargin
=
6.0
;
const
double
_kBottomMargin
=
8.0
;
/// Defines the layout and behavior of a [BottomNavigationBar].
///
/// See also:
...
...
@@ -30,18 +25,16 @@ const double _kBottomMargin = 8.0;
/// * [BottomNavigationBarItem]
/// * <https://material.io/design/components/bottom-navigation.html#specs>
enum
BottomNavigationBarType
{
/// The [BottomNavigationBar]'s [BottomNavigationBarItem]s have fixed width, always
/// display their text labels, and do not shift when tapped.
/// The [BottomNavigationBar]'s [BottomNavigationBarItem]s have fixed width.
fixed
,
/// The location and size of the [BottomNavigationBar] [BottomNavigationBarItem]s
/// animate and labels fade in when they are tapped. Only the selected item
/// displays its text label.
/// animate and labels fade in when they are tapped.
shifting
,
}
/// A material widget
displayed at the bottom of an app for selecting among a
/// small number of views, typically between three and five.
/// A material widget
that's displayed at the bottom of an app for selecting
///
among a
small number of views, typically between three and five.
///
/// The bottom navigation bar consists of multiple items in the form of
/// text labels, icons, or both, laid out on top of a piece of material. It
...
...
@@ -52,18 +45,19 @@ enum BottomNavigationBarType {
/// where it is provided as the [Scaffold.bottomNavigationBar] argument.
///
/// The bottom navigation bar's [type] changes how its [items] are displayed.
/// If not specified
it's automatically set to [BottomNavigationBarType.fixed]
///
when there are less than four items, [BottomNavigationBarType.shifting]
/// otherwise.
/// If not specified
, then it's automatically set to
///
[BottomNavigationBarType.fixed] when there are less than four items, and
///
[BottomNavigationBarType.shifting]
otherwise.
///
/// * [BottomNavigationBarType.fixed], the default when there are less than
/// four [items]. The selected item is rendered with [fixedColor] if it's
/// non-null, otherwise the theme's [ThemeData.primaryColor] is used. The
/// navigation bar's background color is the default [Material] background
/// four [items]. The selected item is rendered with the
/// [selectedItemColor] if it's non-null, otherwise the theme's
/// [ThemeData.primaryColor] is used. If [backgroundColor] is null, The
/// navigation bar's background color defaults to the [Material] background
/// color, [ThemeData.canvasColor] (essentially opaque white).
/// * [BottomNavigationBarType.shifting], the default when there are four
/// or more [items].
All items are rendered in white and the navigation bar's
/// background color is the same as the
/// or more [items].
If [selectedItemColor] is null, all items are rendered
///
in white. The navigation bar's
background color is the same as the
/// [BottomNavigationBarItem.backgroundColor] of the selected item. In this
/// case it's assumed that each item will have a different background color
/// and that background color will contrast well with white.
...
...
@@ -71,10 +65,9 @@ enum BottomNavigationBarType {
/// {@tool snippet --template=stateful_widget_material}
/// This example shows a [BottomNavigationBar] as it is used within a [Scaffold]
/// widget. The [BottomNavigationBar] has three [BottomNavigationBarItem]
/// widgets and the [currentIndex] is set to index 1. The color of the selected
/// item is set to a purple color. A function is called whenever any item is
/// tapped and the function helps display the appropriate [Text] in the body of
/// the [Scaffold].
/// widgets and the [currentIndex] is set to index 1. The selected item is
/// purple. The `_onItemTapped` function changes the selected item's index
/// and displays a corresponding message in the center of the [Scaffold].
///
/// ```dart
/// int _selectedIndex = 1;
...
...
@@ -106,7 +99,7 @@ enum BottomNavigationBarType {
/// BottomNavigationBarItem(icon: Icon(Icons.school), title: Text('School')),
/// ],
/// currentIndex: _selectedIndex,
///
fixed
Color: Colors.deepPurple,
///
selectedItem
Color: Colors.deepPurple,
/// onTap: _onItemTapped,
/// ),
/// );
...
...
@@ -120,25 +113,43 @@ enum BottomNavigationBarType {
/// * [Scaffold]
/// * <https://material.io/design/components/bottom-navigation.html>
class
BottomNavigationBar
extends
StatefulWidget
{
/// Creates a bottom navigation bar
, typically used in a [Scaffold] where it
///
is provided as the
[Scaffold.bottomNavigationBar] argument.
/// Creates a bottom navigation bar
which is typically used as a
///
[Scaffold]'s
[Scaffold.bottomNavigationBar] argument.
///
/// The length of [items] must be at least two and each item's icon and title must be not null.
/// The length of [items] must be at least two and each item's icon and title
/// must not be null.
///
/// If [type] is null then [BottomNavigationBarType.fixed] is used when there
/// are two or three [items], [BottomNavigationBarType.shifting] otherwise.
///
/// If [fixedColor] is null then the theme's primary color,
/// [ThemeData.primaryColor], is used. However if [BottomNavigationBar.type] is
/// [BottomNavigationBarType.shifting] then [fixedColor] is ignored.
/// The [iconSize], [selectedFontSize], [unselectedFontSize], and [elevation]
/// arguments must be non-null and non-negative.
///
/// Only one of [selectedItemColor] and [fixedColor] can be specified. The
/// former is preferred, [fixedColor] only exists for the sake of
/// backwards compatibility.
///
/// The [showSelectedLabels] argument must not be non-null.
///
/// The [showUnselectedLabels] argument defaults to `true` if [type] is
/// [BottomNavigationBarType.fixed] and `false` if [type] is
/// [BottomNavigationBarType.shifting].
BottomNavigationBar
({
Key
key
,
@required
this
.
items
,
this
.
onTap
,
this
.
currentIndex
=
0
,
this
.
elevation
=
8.0
,
BottomNavigationBarType
type
,
this
.
fixedColor
,
Color
fixedColor
,
this
.
backgroundColor
,
this
.
iconSize
=
24.0
,
Color
selectedItemColor
,
this
.
unselectedItemColor
,
this
.
selectedFontSize
=
14.0
,
this
.
unselectedFontSize
=
12.0
,
this
.
showSelectedLabels
=
true
,
bool
showUnselectedLabels
,
})
:
assert
(
items
!=
null
),
assert
(
items
.
length
>=
2
),
assert
(
...
...
@@ -146,42 +157,125 @@ class BottomNavigationBar extends StatefulWidget {
'Every item must have a non-null title'
,
),
assert
(
0
<=
currentIndex
&&
currentIndex
<
items
.
length
),
assert
(
iconSize
!=
null
),
type
=
type
??
(
items
.
length
<=
3
?
BottomNavigationBarType
.
fixed
:
BottomNavigationBarType
.
shifting
),
assert
(
elevation
!=
null
&&
elevation
>=
0.0
),
assert
(
iconSize
!=
null
&&
iconSize
>=
0.0
),
assert
(
selectedItemColor
!=
null
?
fixedColor
==
null
:
true
,
'Either selectedItemColor or fixedColor can be specified, but not both'
),
assert
(
selectedFontSize
!=
null
&&
selectedFontSize
>=
0.0
),
assert
(
unselectedFontSize
!=
null
&&
unselectedFontSize
>=
0.0
),
assert
(
showSelectedLabels
!=
null
),
type
=
_type
(
type
,
items
),
selectedItemColor
=
selectedItemColor
??
fixedColor
,
showUnselectedLabels
=
showUnselectedLabels
??
_defaultShowUnselected
(
_type
(
type
,
items
)),
super
(
key:
key
);
/// The interactive items laid out within the bottom navigation bar where each item has an icon and title.
/// Defines the appearance of the button items that are arrayed within the
/// bottom navigation bar.
final
List
<
BottomNavigationBarItem
>
items
;
///
The callback that is called when a item
is tapped.
///
Called when one of the [items]
is tapped.
///
/// The
widget creating the bottom navigation bar needs to keep track of the
///
current index and call `setState` to rebuild it with the newly provided
///
index
.
/// The
stateful widget that creates the bottom navigation bar needs to keep
///
track of the index of the selected [BottomNavigationBarItem] and call
///
`setState` to rebuild the bottom navigation bar with the new [currentIndex]
.
final
ValueChanged
<
int
>
onTap
;
/// The index into [items]
of the current active item
.
/// The index into [items]
for the current active [BottomNavigationBarItem]
.
final
int
currentIndex
;
/// The z-coordinate of this [BottomNavigationBar].
///
/// If null, defaults to `8.0`.
///
/// {@macro flutter.material.material.elevation}
final
double
elevation
;
/// Defines the layout and behavior of a [BottomNavigationBar].
///
/// See documentation for [BottomNavigationBarType] for information on the
meaning
/// of different types.
/// See documentation for [BottomNavigationBarType] for information on the
///
meaning
of different types.
final
BottomNavigationBarType
type
;
/// The color of the selected item when bottom navigation bar is
/// [BottomNavigationBarType.fixed].
/// The value of [selectedItemColor].
///
/// This getter only exists for backwards compatibility, the
/// [selectedItemColor] property is preferred.
Color
get
fixedColor
=>
selectedItemColor
;
/// The color of the [BottomNavigationBar] itself.
///
/// If [
fixedColor] is null then the theme's primary color,
/// [
ThemeData.primaryColor], is used. However if [BottomNavigationBar.type] i
s
///
[BottomNavigationBarType.shifting] then [fixedColor] is ignored
.
final
Color
fixe
dColor
;
/// If [
type] is [BottomNavigationBarType.shifting] and the
/// [
items]s, have [BottomNavigationBarItem.backgroundColor] set, the [item]'
s
///
backgroundColor will splash and overwrite this color
.
final
Color
backgroun
dColor
;
/// The size of all of the [BottomNavigationBarItem] icons.
///
/// See [BottomNavigationBarItem.icon] for more information.
final
double
iconSize
;
/// The color of the selected [BottomNavigationBarItem.icon] and
/// [BottomNavigationBarItem.label].
///
/// If null then the [ThemeData.primaryColor] is used.
final
Color
selectedItemColor
;
/// The color of the unselected [BottomNavigationBarItem.icon] and
/// [BottomNavigationBarItem.label]s.
///
/// If null then the [TextTheme.caption]'s color is used.
final
Color
unselectedItemColor
;
/// The font size of the [BottomNavigationBarItem] labels when they are selected.
///
/// Defaults to `14.0`.
final
double
selectedFontSize
;
/// The font size of the [BottomNavigationBarItem] labels when they are not
/// selected.
///
/// Defaults to `12.0`.
final
double
unselectedFontSize
;
/// Whether the labels are shown for the selected [BottomNavigationBarItem].
final
bool
showUnselectedLabels
;
/// Whether the labels are shown for the unselected [BottomNavigationBarItem]s.
final
bool
showSelectedLabels
;
// Used by the [BottomNavigationBar] constructor to set the [type] parameter.
//
// If type is provided, it is returned. Otherwise,
// [BottomNavigationBarType.fixed] is used for 3 or fewer items, and
// [BottomNavigationBarType.shifting] is used for 4+ items.
static
BottomNavigationBarType
_type
(
BottomNavigationBarType
type
,
List
<
BottomNavigationBarItem
>
items
,
)
{
if
(
type
!=
null
)
{
return
type
;
}
return
items
.
length
<=
3
?
BottomNavigationBarType
.
fixed
:
BottomNavigationBarType
.
shifting
;
}
// Used by the [BottomNavigationBar] constructor to set the [showUnselected]
// parameter.
//
// Unselected labels are shown by default for [BottomNavigationBarType.fixed],
// and hidden by default for [BottomNavigationBarType.shifting].
static
bool
_defaultShowUnselected
(
BottomNavigationBarType
type
)
{
switch
(
type
)
{
case
BottomNavigationBarType
.
shifting
:
return
false
;
case
BottomNavigationBarType
.
fixed
:
return
true
;
}
assert
(
false
);
return
false
;
}
@override
_BottomNavigationBarState
createState
()
=>
_BottomNavigationBarState
();
}
...
...
@@ -198,8 +292,17 @@ class _BottomNavigationTile extends StatelessWidget {
this
.
colorTween
,
this
.
flex
,
this
.
selected
=
false
,
@required
this
.
selectedFontSize
,
@required
this
.
unselectedFontSize
,
this
.
showSelectedLabels
,
this
.
showUnselectedLabels
,
this
.
indexLabel
,
})
:
assert
(
selected
!=
null
);
})
:
assert
(
type
!=
null
),
assert
(
item
!=
null
),
assert
(
animation
!=
null
),
assert
(
selected
!=
null
),
assert
(
selectedFontSize
!=
null
&&
selectedFontSize
>=
0
),
assert
(
unselectedFontSize
!=
null
&&
unselectedFontSize
>=
0
);
final
BottomNavigationBarType
type
;
final
BottomNavigationBarItem
item
;
...
...
@@ -209,7 +312,11 @@ class _BottomNavigationTile extends StatelessWidget {
final
ColorTween
colorTween
;
final
double
flex
;
final
bool
selected
;
final
double
selectedFontSize
;
final
double
unselectedFontSize
;
final
String
indexLabel
;
final
bool
showSelectedLabels
;
final
bool
showUnselectedLabels
;
@override
Widget
build
(
BuildContext
context
)
{
...
...
@@ -218,16 +325,50 @@ class _BottomNavigationTile extends StatelessWidget {
// produce smooth animation. We do this by multiplying the flex value
// (which is an integer) by a large number.
int
size
;
Widget
label
;
double
bottomPadding
=
selectedFontSize
/
2.0
;
double
topPadding
=
selectedFontSize
/
2.0
;
// Defines the padding for the animating icons + labels.
//
// The animations go from "Unselected":
// =======
// | <-- Padding equal to the text height.
// | ☆
// | text <-- Invisible text.
// =======
//
// To "Selected":
//
// =======
// | <-- Padding equal to 1/2 text height.
// | ☆
// | text
// | <-- Padding equal to 1/2 text height.
// =======
if
(
showSelectedLabels
&&
!
showUnselectedLabels
)
{
bottomPadding
=
Tween
<
double
>(
begin:
0.0
,
end:
selectedFontSize
/
2.0
,
).
evaluate
(
animation
);
topPadding
=
Tween
<
double
>(
begin:
selectedFontSize
,
end:
selectedFontSize
/
2.0
,
).
evaluate
(
animation
);
}
// Center all icons if no labels are shown.
if
(!
showSelectedLabels
&&
!
showUnselectedLabels
)
{
bottomPadding
=
0.0
;
topPadding
=
selectedFontSize
;
}
switch
(
type
)
{
case
BottomNavigationBarType
.
fixed
:
size
=
1
;
label
=
_FixedLabel
(
colorTween:
colorTween
,
animation:
animation
,
item:
item
);
break
;
case
BottomNavigationBarType
.
shifting
:
size
=
(
flex
*
1000.0
).
round
();
label
=
_ShiftingLabel
(
animation:
animation
,
item:
item
);
break
;
}
...
...
@@ -241,21 +382,31 @@ class _BottomNavigationTile extends StatelessWidget {
children:
<
Widget
>[
InkResponse
(
onTap:
onTap
,
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
center
,
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
mainAxisSize:
MainAxisSize
.
min
,
children:
<
Widget
>[
_TileIcon
(
type:
type
,
colorTween:
colorTween
,
animation:
animation
,
iconSize:
iconSize
,
selected:
selected
,
item:
item
,
),
label
,
],
child:
Padding
(
padding:
EdgeInsets
.
only
(
top:
topPadding
,
bottom:
bottomPadding
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
center
,
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
mainAxisSize:
MainAxisSize
.
min
,
children:
<
Widget
>[
_TileIcon
(
colorTween:
colorTween
,
animation:
animation
,
iconSize:
iconSize
,
selected:
selected
,
item:
item
,
),
_Label
(
colorTween:
colorTween
,
animation:
animation
,
item:
item
,
selectedFontSize:
selectedFontSize
,
unselectedFontSize:
unselectedFontSize
,
showSelectedLabels:
showSelectedLabels
,
showUnselectedLabels:
showUnselectedLabels
,
),
],
),
),
),
Semantics
(
...
...
@@ -272,15 +423,15 @@ class _BottomNavigationTile extends StatelessWidget {
class
_TileIcon
extends
StatelessWidget
{
const
_TileIcon
({
Key
key
,
@required
this
.
type
,
@required
this
.
colorTween
,
@required
this
.
animation
,
@required
this
.
iconSize
,
@required
this
.
selected
,
@required
this
.
item
,
})
:
super
(
key:
key
);
})
:
assert
(
selected
!=
null
),
assert
(
item
!=
null
),
super
(
key:
key
);
final
BottomNavigationBarType
type
;
final
ColorTween
colorTween
;
final
Animation
<
double
>
animation
;
final
double
iconSize
;
...
...
@@ -289,28 +440,11 @@ class _TileIcon extends StatelessWidget {
@override
Widget
build
(
BuildContext
context
)
{
double
tweenStart
;
Color
iconColor
;
switch
(
type
)
{
case
BottomNavigationBarType
.
fixed
:
tweenStart
=
8.0
;
iconColor
=
colorTween
.
evaluate
(
animation
);
break
;
case
BottomNavigationBarType
.
shifting
:
tweenStart
=
16.0
;
iconColor
=
Colors
.
white
;
break
;
}
final
Color
iconColor
=
colorTween
.
evaluate
(
animation
);
return
Align
(
alignment:
Alignment
.
topCenter
,
heightFactor:
1.0
,
child:
Container
(
margin:
EdgeInsets
.
only
(
top:
Tween
<
double
>(
begin:
tweenStart
,
end:
_kTopMargin
,
).
evaluate
(
animation
),
),
child:
IconTheme
(
data:
IconThemeData
(
color:
iconColor
,
...
...
@@ -323,89 +457,84 @@ class _TileIcon extends StatelessWidget {
}
}
class
_
Fixed
Label
extends
StatelessWidget
{
const
_
Fixed
Label
({
class
_Label
extends
StatelessWidget
{
const
_Label
({
Key
key
,
@required
this
.
colorTween
,
@required
this
.
animation
,
@required
this
.
item
,
})
:
super
(
key:
key
);
@required
this
.
selectedFontSize
,
@required
this
.
unselectedFontSize
,
@required
this
.
showSelectedLabels
,
@required
this
.
showUnselectedLabels
,
})
:
assert
(
colorTween
!=
null
),
assert
(
animation
!=
null
),
assert
(
item
!=
null
),
assert
(
selectedFontSize
!=
null
),
assert
(
unselectedFontSize
!=
null
),
assert
(
showSelectedLabels
!=
null
),
assert
(
showUnselectedLabels
!=
null
),
super
(
key:
key
);
final
ColorTween
colorTween
;
final
Animation
<
double
>
animation
;
final
BottomNavigationBarItem
item
;
final
double
selectedFontSize
;
final
double
unselectedFontSize
;
final
bool
showSelectedLabels
;
final
bool
showUnselectedLabels
;
@override
Widget
build
(
BuildContext
context
)
{
return
Align
(
alignment:
Alignment
.
bottomCenter
,
heightFactor:
1.0
,
child:
Container
(
margin:
const
EdgeInsets
.
only
(
bottom:
_kBottomMargin
),
child:
DefaultTextStyle
.
merge
(
style:
TextStyle
(
fontSize:
_kActiveFontSize
,
color:
colorTween
.
evaluate
(
animation
),
),
// The font size should grow here when active, but because of the way
// font rendering works, it doesn't grow smoothly if we just animate
// the font size, so we use a transform instead.
child:
Transform
(
transform:
Matrix4
.
diagonal3
(
Vector3
.
all
(
Tween
<
double
>(
begin:
_kInactiveFontSize
/
_kActiveFontSize
,
end:
1.0
,
).
evaluate
(
animation
),
),
),
alignment:
Alignment
.
bottomCenter
,
child:
item
.
title
,
Widget
text
=
DefaultTextStyle
.
merge
(
style:
TextStyle
(
fontSize:
selectedFontSize
,
color:
colorTween
.
evaluate
(
animation
),
),
// The font size should grow here when active, but because of the way
// font rendering works, it doesn't grow smoothly if we just animate
// the font size, so we use a transform instead.
child:
Transform
(
transform:
Matrix4
.
diagonal3
(
Vector3
.
all
(
Tween
<
double
>(
begin:
unselectedFontSize
/
selectedFontSize
,
end:
1.0
,
).
evaluate
(
animation
),
),
),
alignment:
Alignment
.
bottomCenter
,
child:
item
.
title
,
),
);
}
}
class
_ShiftingLabel
extends
StatelessWidget
{
const
_ShiftingLabel
({
Key
key
,
@required
this
.
animation
,
@required
this
.
item
,
})
:
super
(
key:
key
);
final
Animation
<
double
>
animation
;
final
BottomNavigationBarItem
item
;
if
(!
showUnselectedLabels
&&
!
showSelectedLabels
)
{
// Never show any labels.
text
=
Opacity
(
alwaysIncludeSemantics:
true
,
opacity:
0.0
,
child:
text
,
);
}
else
if
(!
showUnselectedLabels
)
{
// Fade selected labels in.
text
=
FadeTransition
(
alwaysIncludeSemantics:
true
,
opacity:
animation
,
child:
text
,
);
}
else
if
(!
showSelectedLabels
)
{
// Fade selected labels out.
text
=
FadeTransition
(
alwaysIncludeSemantics:
true
,
opacity:
Tween
<
double
>(
begin:
1.0
,
end:
0.0
).
animate
(
animation
),
child:
text
,
);
}
@override
Widget
build
(
BuildContext
context
)
{
return
Align
(
alignment:
Alignment
.
bottomCenter
,
heightFactor:
1.0
,
child:
Container
(
margin:
EdgeInsets
.
only
(
bottom:
Tween
<
double
>(
// In the spec, they just remove the label for inactive items and
// specify a 16dp bottom margin. We don't want to actually remove
// the label because we want to fade it in and out, so this modifies
// the bottom margin to take that into account.
begin:
2.0
,
end:
_kBottomMargin
,
).
evaluate
(
animation
),
),
child:
FadeTransition
(
alwaysIncludeSemantics:
true
,
opacity:
animation
,
child:
DefaultTextStyle
.
merge
(
style:
const
TextStyle
(
fontSize:
_kActiveFontSize
,
color:
Colors
.
white
,
),
child:
item
.
title
,
),
),
),
child:
Container
(
child:
text
),
);
}
}
...
...
@@ -529,63 +658,57 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
List
<
Widget
>
_createTiles
()
{
final
MaterialLocalizations
localizations
=
MaterialLocalizations
.
of
(
context
);
assert
(
localizations
!=
null
);
final
List
<
Widget
>
children
=
<
Widget
>[];
final
ThemeData
themeData
=
Theme
.
of
(
context
);
Color
themeColor
;
switch
(
themeData
.
brightness
)
{
case
Brightness
.
light
:
themeColor
=
themeData
.
primaryColor
;
break
;
case
Brightness
.
dark
:
themeColor
=
themeData
.
accentColor
;
break
;
}
ColorTween
colorTween
;
switch
(
widget
.
type
)
{
case
BottomNavigationBarType
.
fixed
:
final
ThemeData
themeData
=
Theme
.
of
(
context
);
final
TextTheme
textTheme
=
themeData
.
textTheme
;
Color
themeColor
;
switch
(
themeData
.
brightness
)
{
case
Brightness
.
light
:
themeColor
=
themeData
.
primaryColor
;
break
;
case
Brightness
.
dark
:
themeColor
=
themeData
.
accentColor
;
break
;
}
final
ColorTween
colorTween
=
ColorTween
(
begin:
textTheme
.
caption
.
color
,
end:
widget
.
fixedColor
??
themeColor
,
colorTween
=
ColorTween
(
begin:
widget
.
unselectedItemColor
??
themeData
.
textTheme
.
caption
.
color
,
end:
widget
.
selectedItemColor
??
widget
.
fixedColor
??
themeColor
,
);
for
(
int
i
=
0
;
i
<
widget
.
items
.
length
;
i
+=
1
)
{
children
.
add
(
_BottomNavigationTile
(
widget
.
type
,
widget
.
items
[
i
],
_animations
[
i
],
widget
.
iconSize
,
onTap:
()
{
if
(
widget
.
onTap
!=
null
)
widget
.
onTap
(
i
);
},
colorTween:
colorTween
,
selected:
i
==
widget
.
currentIndex
,
indexLabel:
localizations
.
tabLabel
(
tabIndex:
i
+
1
,
tabCount:
widget
.
items
.
length
),
),
);
}
break
;
case
BottomNavigationBarType
.
shifting
:
for
(
int
i
=
0
;
i
<
widget
.
items
.
length
;
i
+=
1
)
{
children
.
add
(
_BottomNavigationTile
(
widget
.
type
,
widget
.
items
[
i
],
_animations
[
i
],
widget
.
iconSize
,
onTap:
()
{
if
(
widget
.
onTap
!=
null
)
widget
.
onTap
(
i
);
},
flex:
_evaluateFlex
(
_animations
[
i
]),
selected:
i
==
widget
.
currentIndex
,
indexLabel:
localizations
.
tabLabel
(
tabIndex:
i
+
1
,
tabCount:
widget
.
items
.
length
),
),
);
}
colorTween
=
ColorTween
(
begin:
widget
.
unselectedItemColor
??
Colors
.
white
,
end:
widget
.
selectedItemColor
??
Colors
.
white
,
);
break
;
}
return
children
;
final
List
<
Widget
>
tiles
=
<
Widget
>[];
for
(
int
i
=
0
;
i
<
widget
.
items
.
length
;
i
++)
{
tiles
.
add
(
_BottomNavigationTile
(
widget
.
type
,
widget
.
items
[
i
],
_animations
[
i
],
widget
.
iconSize
,
selectedFontSize:
widget
.
selectedFontSize
,
unselectedFontSize:
widget
.
unselectedFontSize
,
onTap:
()
{
if
(
widget
.
onTap
!=
null
)
widget
.
onTap
(
i
);
},
colorTween:
colorTween
,
flex:
_evaluateFlex
(
_animations
[
i
]),
selected:
i
==
widget
.
currentIndex
,
showSelectedLabels:
widget
.
showSelectedLabels
,
showUnselectedLabels:
widget
.
showUnselectedLabels
,
indexLabel:
localizations
.
tabLabel
(
tabIndex:
i
+
1
,
tabCount:
widget
.
items
.
length
),
));
}
return
tiles
;
}
Widget
_createContainer
(
List
<
Widget
>
tiles
)
{
...
...
@@ -602,12 +725,14 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
Widget
build
(
BuildContext
context
)
{
assert
(
debugCheckHasDirectionality
(
context
));
assert
(
debugCheckHasMaterialLocalizations
(
context
));
assert
(
debugCheckHasMediaQuery
(
context
));
// Labels apply up to _bottomMargin padding. Remainder is media padding.
final
double
additionalBottomPadding
=
math
.
max
(
MediaQuery
.
of
(
context
).
padding
.
bottom
-
_kBottomMargin
,
0.0
);
final
double
additionalBottomPadding
=
math
.
max
(
MediaQuery
.
of
(
context
).
padding
.
bottom
-
widget
.
selectedFontSize
/
2.0
,
0.0
);
Color
backgroundColor
;
switch
(
widget
.
type
)
{
case
BottomNavigationBarType
.
fixed
:
backgroundColor
=
widget
.
backgroundColor
;
break
;
case
BottomNavigationBarType
.
shifting
:
backgroundColor
=
_backgroundColor
;
...
...
@@ -616,7 +741,7 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
return
Semantics
(
explicitChildNodes:
true
,
child:
Material
(
elevation:
8.0
,
elevation:
widget
.
elevation
,
color:
backgroundColor
,
child:
ConstrainedBox
(
constraints:
BoxConstraints
(
minHeight:
kBottomNavigationBarHeight
+
additionalBottomPadding
),
...
...
packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart
View file @
617ca627
...
...
@@ -9,8 +9,8 @@ import 'framework.dart';
/// An interactive button within either material's [BottomNavigationBar]
/// or the iOS themed [CupertinoTabBar] with an icon and title.
///
/// This class is rarely used in isolation.
Commonly embedded in one of the
/// bottom navigation widgets above.
/// This class is rarely used in isolation.
It is typically embedded in one of
///
the
bottom navigation widgets above.
///
/// See also:
///
...
...
@@ -67,7 +67,7 @@ class BottomNavigationBarItem {
///
/// If the navigation bar's type is [BottomNavigationBarType.shifting], then
/// the entire bar is flooded with the [backgroundColor] when this item is
/// tapped.
/// tapped.
This will override [BottomNavigationBar.backgroundColor].
///
/// Not used for [CupertinoTabBar]. Control the invariant bar color directly
/// via [CupertinoTabBar.backgroundColor].
...
...
packages/flutter/test/material/bottom_navigation_bar_test.dart
View file @
617ca627
...
...
@@ -6,7 +6,9 @@ import 'dart:io';
import
'dart:ui'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:vector_math/vector_math_64.dart'
show
Vector3
;
import
'../rendering/mock_canvas.dart'
;
import
'../widgets/semantics_tester.dart'
;
...
...
@@ -68,6 +70,325 @@ void main() {
expect
(
find
.
text
(
'Alarm'
),
findsOneWidget
);
});
testWidgets
(
'Fixed BottomNavigationBar defaults'
,
(
WidgetTester
tester
)
async
{
const
Color
primaryColor
=
Colors
.
black
;
const
Color
captionColor
=
Colors
.
purple
;
await
tester
.
pumpWidget
(
MaterialApp
(
theme:
ThemeData
(
primaryColor:
primaryColor
,
textTheme:
const
TextTheme
(
caption:
TextStyle
(
color:
captionColor
)),
),
home:
Scaffold
(
bottomNavigationBar:
BottomNavigationBar
(
type:
BottomNavigationBarType
.
fixed
,
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
title:
Text
(
'AC'
),
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
title:
Text
(
'Alarm'
),
),
]
)
)
)
);
const
double
selectedFontSize
=
14.0
;
const
double
unselectedFontSize
=
12.0
;
expect
(
tester
.
renderObject
<
RenderParagraph
>(
find
.
text
(
'AC'
)).
text
.
style
.
fontSize
,
selectedFontSize
);
// Unselected label has a font size of 14 but is scaled down to be font size 12.
expect
(
tester
.
renderObject
<
RenderParagraph
>(
find
.
text
(
'Alarm'
)).
text
.
style
.
fontSize
,
selectedFontSize
);
expect
(
tester
.
firstWidget
<
Transform
>(
find
.
ancestor
(
of:
find
.
text
(
'Alarm'
),
matching:
find
.
byType
(
Transform
))).
transform
,
equals
(
Matrix4
.
diagonal3
(
Vector3
.
all
(
unselectedFontSize
/
selectedFontSize
))),
);
expect
(
tester
.
renderObject
<
RenderParagraph
>(
find
.
text
(
'AC'
)).
text
.
style
.
color
,
equals
(
primaryColor
));
expect
(
tester
.
renderObject
<
RenderParagraph
>(
find
.
text
(
'Alarm'
)).
text
.
style
.
color
,
equals
(
captionColor
));
expect
(
_getOpacity
(
tester
,
'Alarm'
),
equals
(
1.0
));
expect
(
_getMaterial
(
tester
).
elevation
,
equals
(
8.0
));
});
testWidgets
(
'Shifting BottomNavigationBar defaults'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
bottomNavigationBar:
BottomNavigationBar
(
type:
BottomNavigationBarType
.
shifting
,
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
title:
Text
(
'AC'
),
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
title:
Text
(
'Alarm'
),
),
]
)
)
)
);
const
double
selectedFontSize
=
14.0
;
expect
(
tester
.
renderObject
<
RenderParagraph
>(
find
.
text
(
'AC'
)).
text
.
style
.
fontSize
,
selectedFontSize
);
expect
(
tester
.
renderObject
<
RenderParagraph
>(
find
.
text
(
'AC'
)).
text
.
style
.
color
,
equals
(
Colors
.
white
));
expect
(
_getOpacity
(
tester
,
'Alarm'
),
equals
(
0.0
));
expect
(
_getMaterial
(
tester
).
elevation
,
equals
(
8.0
));
});
testWidgets
(
'Fixed BottomNavigationBar custom font size, color'
,
(
WidgetTester
tester
)
async
{
const
Color
primaryColor
=
Colors
.
black
;
const
Color
captionColor
=
Colors
.
purple
;
const
Color
selectedColor
=
Colors
.
blue
;
const
Color
unselectedColor
=
Colors
.
yellow
;
const
double
selectedFontSize
=
18.0
;
const
double
unselectedFontSize
=
14.0
;
await
tester
.
pumpWidget
(
MaterialApp
(
theme:
ThemeData
(
primaryColor:
primaryColor
,
textTheme:
const
TextTheme
(
caption:
TextStyle
(
color:
captionColor
)),
),
home:
Scaffold
(
bottomNavigationBar:
BottomNavigationBar
(
type:
BottomNavigationBarType
.
fixed
,
selectedFontSize:
selectedFontSize
,
unselectedFontSize:
unselectedFontSize
,
selectedItemColor:
selectedColor
,
unselectedItemColor:
unselectedColor
,
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
title:
Text
(
'AC'
),
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
title:
Text
(
'Alarm'
),
),
]
)
)
)
);
expect
(
tester
.
renderObject
<
RenderParagraph
>(
find
.
text
(
'AC'
)).
text
.
style
.
fontSize
,
selectedFontSize
);
// Unselected label has a font size of 18 but is scaled down to be font size 14.
expect
(
tester
.
renderObject
<
RenderParagraph
>(
find
.
text
(
'Alarm'
)).
text
.
style
.
fontSize
,
selectedFontSize
);
expect
(
tester
.
firstWidget
<
Transform
>(
find
.
ancestor
(
of:
find
.
text
(
'Alarm'
),
matching:
find
.
byType
(
Transform
))).
transform
,
equals
(
Matrix4
.
diagonal3
(
Vector3
.
all
(
unselectedFontSize
/
selectedFontSize
))),
);
expect
(
tester
.
renderObject
<
RenderParagraph
>(
find
.
text
(
'AC'
)).
text
.
style
.
color
,
equals
(
selectedColor
));
expect
(
tester
.
renderObject
<
RenderParagraph
>(
find
.
text
(
'Alarm'
)).
text
.
style
.
color
,
equals
(
unselectedColor
));
expect
(
_getOpacity
(
tester
,
'Alarm'
),
equals
(
1.0
));
});
testWidgets
(
'Shifting BottomNavigationBar custom font size, color'
,
(
WidgetTester
tester
)
async
{
const
Color
primaryColor
=
Colors
.
black
;
const
Color
captionColor
=
Colors
.
purple
;
const
Color
selectedColor
=
Colors
.
blue
;
const
Color
unselectedColor
=
Colors
.
yellow
;
const
double
selectedFontSize
=
18.0
;
const
double
unselectedFontSize
=
14.0
;
await
tester
.
pumpWidget
(
MaterialApp
(
theme:
ThemeData
(
primaryColor:
primaryColor
,
textTheme:
const
TextTheme
(
caption:
TextStyle
(
color:
captionColor
)),
),
home:
Scaffold
(
bottomNavigationBar:
BottomNavigationBar
(
type:
BottomNavigationBarType
.
shifting
,
selectedFontSize:
selectedFontSize
,
unselectedFontSize:
unselectedFontSize
,
selectedItemColor:
selectedColor
,
unselectedItemColor:
unselectedColor
,
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
title:
Text
(
'AC'
),
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
title:
Text
(
'Alarm'
),
),
]
)
)
)
);
expect
(
tester
.
renderObject
<
RenderParagraph
>(
find
.
text
(
'AC'
)).
text
.
style
.
fontSize
,
selectedFontSize
);
expect
(
tester
.
renderObject
<
RenderParagraph
>(
find
.
text
(
'AC'
)).
text
.
style
.
color
,
equals
(
selectedColor
));
expect
(
_getOpacity
(
tester
,
'Alarm'
),
equals
(
0.0
));
});
testWidgets
(
'Fixed BottomNavigationBar can hide unselected labels'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
bottomNavigationBar:
BottomNavigationBar
(
type:
BottomNavigationBarType
.
fixed
,
showUnselectedLabels:
false
,
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
title:
Text
(
'AC'
),
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
title:
Text
(
'Alarm'
),
),
]
)
)
)
);
expect
(
_getOpacity
(
tester
,
'AC'
),
equals
(
1.0
));
expect
(
_getOpacity
(
tester
,
'Alarm'
),
equals
(
0.0
));
});
testWidgets
(
'Fixed BottomNavigationBar can update background color'
,
(
WidgetTester
tester
)
async
{
const
Color
color
=
Colors
.
yellow
;
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
bottomNavigationBar:
BottomNavigationBar
(
type:
BottomNavigationBarType
.
fixed
,
backgroundColor:
color
,
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
title:
Text
(
'AC'
),
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
title:
Text
(
'Alarm'
),
),
]
)
)
)
);
expect
(
_getMaterial
(
tester
).
color
,
equals
(
color
));
});
testWidgets
(
'Shifting BottomNavigationBar background color is overriden by item color'
,
(
WidgetTester
tester
)
async
{
const
Color
itemColor
=
Colors
.
yellow
;
const
Color
backgroundColor
=
Colors
.
blue
;
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
bottomNavigationBar:
BottomNavigationBar
(
type:
BottomNavigationBarType
.
shifting
,
backgroundColor:
backgroundColor
,
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
title:
Text
(
'AC'
),
backgroundColor:
itemColor
,
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
title:
Text
(
'Alarm'
),
),
]
)
)
)
);
expect
(
_getMaterial
(
tester
).
color
,
equals
(
itemColor
));
});
testWidgets
(
'Specifying both selectedItemColor and fixedColor asserts'
,
(
WidgetTester
tester
)
async
{
expect
(
()
{
return
BottomNavigationBar
(
selectedItemColor:
Colors
.
black
,
fixedColor:
Colors
.
black
,
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
title:
Text
(
'AC'
),
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
title:
Text
(
'Alarm'
),
),
],
);
},
throwsAssertionError
,
);
});
testWidgets
(
'Fixed BottomNavigationBar uses fixedColor when selectedItemColor not provided'
,
(
WidgetTester
tester
)
async
{
const
Color
fixedColor
=
Colors
.
black
;
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
bottomNavigationBar:
BottomNavigationBar
(
type:
BottomNavigationBarType
.
fixed
,
fixedColor:
fixedColor
,
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
title:
Text
(
'AC'
),
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
title:
Text
(
'Alarm'
),
),
]
)
)
)
);
expect
(
tester
.
renderObject
<
RenderParagraph
>(
find
.
text
(
'AC'
)).
text
.
style
.
color
,
equals
(
fixedColor
));
});
testWidgets
(
'setting selectedFontSize to zero hides all labels'
,
(
WidgetTester
tester
)
async
{
const
double
customElevation
=
3.0
;
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
bottomNavigationBar:
BottomNavigationBar
(
type:
BottomNavigationBarType
.
fixed
,
elevation:
customElevation
,
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
title:
Text
(
'AC'
),
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
title:
Text
(
'Alarm'
),
),
]
)
)
)
);
expect
(
_getMaterial
(
tester
).
elevation
,
equals
(
customElevation
));
});
testWidgets
(
'BottomNavigationBar adds bottom padding to height'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
MaterialApp
(
...
...
@@ -91,7 +412,7 @@ void main() {
)
);
const
double
labelBottomMargin
=
8.0
;
// _kBottomMargin in implementation
.
const
double
labelBottomMargin
=
7.0
;
// 7 == defaulted selectedFontSize / 2.0
.
const
double
additionalPadding
=
40.0
-
labelBottomMargin
;
const
double
expectedHeight
=
kBottomNavigationBarHeight
+
additionalPadding
;
expect
(
tester
.
getSize
(
find
.
byType
(
BottomNavigationBar
)).
height
,
expectedHeight
);
...
...
@@ -393,7 +714,7 @@ void main() {
);
final
RenderBox
box
=
tester
.
renderObject
(
find
.
byType
(
BottomNavigationBar
));
expect
(
box
.
size
.
height
,
equals
(
6
8
.0
));
expect
(
box
.
size
.
height
,
equals
(
6
6
.0
));
});
testWidgets
(
'BottomNavigationBar limits width of tiles with long titles'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -827,7 +1148,7 @@ void main() {
await
tester
.
pump
(
const
Duration
(
milliseconds:
30
));
await
expectLater
(
find
.
byType
(
BottomNavigationBar
),
matchesGoldenFile
(
'bottom_navigation_bar.shifting_transition.
$pump
.png'
),
matchesGoldenFile
(
'bottom_navigation_bar.shifting_transition.
2.
$pump
.png'
),
skip:
!
Platform
.
isLinux
,
);
}
...
...
@@ -851,6 +1172,191 @@ void main() {
])));
},
throwsA
(
isInstanceOf
<
AssertionError
>()));
});
testWidgets
(
'BottomNavigationBar [showSelectedLabels]=false and [showUnselectedLabels]=false '
'for shifting navbar, expect that there is no rendered text'
,
(
WidgetTester
tester
)
async
{
final
Widget
widget
=
MaterialApp
(
home:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
Scaffold
(
bottomNavigationBar:
BottomNavigationBar
(
showSelectedLabels:
false
,
showUnselectedLabels:
false
,
type:
BottomNavigationBarType
.
shifting
,
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
title:
Text
(
'Red'
),
backgroundColor:
Colors
.
red
,
icon:
Icon
(
Icons
.
dashboard
),
),
BottomNavigationBarItem
(
title:
Text
(
'Green'
),
backgroundColor:
Colors
.
green
,
icon:
Icon
(
Icons
.
menu
),
),
],
),
);
},
),
);
await
tester
.
pumpWidget
(
widget
);
expect
(
find
.
text
(
'Red'
),
findsOneWidget
);
expect
(
find
.
text
(
'Green'
),
findsOneWidget
);
expect
(
tester
.
widget
<
Opacity
>(
find
.
byType
(
Opacity
).
first
).
opacity
,
0.0
);
expect
(
tester
.
widget
<
Opacity
>(
find
.
byType
(
Opacity
).
last
).
opacity
,
0.0
);
});
testWidgets
(
'BottomNavigationBar [showSelectedLabels]=false and [showUnselectedLabels]=false '
'for fixed navbar, expect that there is no rendered text'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
MaterialApp
(
home:
StatefulBuilder
(
builder:
(
BuildContext
context
,
StateSetter
setState
)
{
return
Scaffold
(
bottomNavigationBar:
BottomNavigationBar
(
showSelectedLabels:
false
,
showUnselectedLabels:
false
,
type:
BottomNavigationBarType
.
fixed
,
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
title:
Text
(
'Red'
),
backgroundColor:
Colors
.
red
,
icon:
Icon
(
Icons
.
dashboard
),
),
BottomNavigationBarItem
(
title:
Text
(
'Green'
),
backgroundColor:
Colors
.
green
,
icon:
Icon
(
Icons
.
menu
),
),
],
),
);
},
),
),
);
expect
(
find
.
text
(
'Red'
),
findsOneWidget
);
expect
(
find
.
text
(
'Green'
),
findsOneWidget
);
expect
(
tester
.
widget
<
Opacity
>(
find
.
byType
(
Opacity
).
first
).
opacity
,
0.0
);
expect
(
tester
.
widget
<
Opacity
>(
find
.
byType
(
Opacity
).
last
).
opacity
,
0.0
);
});
testWidgets
(
'BottomNavigationBar.fixed [showSelectedLabels]=false and [showUnselectedLabels]=false semantics'
,
(
WidgetTester
tester
)
async
{
final
SemanticsTester
semantics
=
SemanticsTester
(
tester
);
await
tester
.
pumpWidget
(
boilerplate
(
textDirection:
TextDirection
.
ltr
,
bottomNavigationBar:
BottomNavigationBar
(
showSelectedLabels:
false
,
showUnselectedLabels:
false
,
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
title:
Text
(
'Red'
),
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
title:
Text
(
'Green'
),
),
],
),
),
);
final
TestSemantics
expected
=
TestSemantics
.
root
(
children:
<
TestSemantics
>[
TestSemantics
(
children:
<
TestSemantics
>[
TestSemantics
(
children:
<
TestSemantics
>[
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isSelected
,
SemanticsFlag
.
isHeader
,
],
actions:
<
SemanticsAction
>[
SemanticsAction
.
tap
],
label:
'Red
\n
Tab 1 of 2'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHeader
,
],
actions:
<
SemanticsAction
>[
SemanticsAction
.
tap
],
label:
'Green
\n
Tab 2 of 2'
,
textDirection:
TextDirection
.
ltr
,
),
],
),
],
),
],
);
expect
(
semantics
,
hasSemantics
(
expected
,
ignoreId:
true
,
ignoreTransform:
true
,
ignoreRect:
true
));
semantics
.
dispose
();
});
testWidgets
(
'BottomNavigationBar.shifting [showSelectedLabels]=false and [showUnselectedLabels]=false semantics'
,
(
WidgetTester
tester
)
async
{
final
SemanticsTester
semantics
=
SemanticsTester
(
tester
);
await
tester
.
pumpWidget
(
boilerplate
(
textDirection:
TextDirection
.
ltr
,
bottomNavigationBar:
BottomNavigationBar
(
showSelectedLabels:
false
,
showUnselectedLabels:
false
,
type:
BottomNavigationBarType
.
shifting
,
items:
const
<
BottomNavigationBarItem
>[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
ac_unit
),
title:
Text
(
'Red'
),
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
access_alarm
),
title:
Text
(
'Green'
),
),
],
),
),
);
final
TestSemantics
expected
=
TestSemantics
.
root
(
children:
<
TestSemantics
>[
TestSemantics
(
children:
<
TestSemantics
>[
TestSemantics
(
children:
<
TestSemantics
>[
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isSelected
,
SemanticsFlag
.
isHeader
,
],
actions:
<
SemanticsAction
>[
SemanticsAction
.
tap
],
label:
'Red
\n
Tab 1 of 2'
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
flags:
<
SemanticsFlag
>[
SemanticsFlag
.
isHeader
,
],
actions:
<
SemanticsAction
>[
SemanticsAction
.
tap
],
label:
'Green
\n
Tab 2 of 2'
,
textDirection:
TextDirection
.
ltr
,
),
],
),
],
),
],
);
expect
(
semantics
,
hasSemantics
(
expected
,
ignoreId:
true
,
ignoreTransform:
true
,
ignoreRect:
true
));
semantics
.
dispose
();
});
}
Widget
boilerplate
(
{
Widget
bottomNavigationBar
,
@required
TextDirection
textDirection
})
{
...
...
@@ -874,3 +1380,19 @@ Widget boilerplate({ Widget bottomNavigationBar, @required TextDirection textDir
),
);
}
double
_getOpacity
(
WidgetTester
tester
,
String
textValue
)
{
final
FadeTransition
opacityWidget
=
tester
.
widget
<
FadeTransition
>(
find
.
ancestor
(
of:
find
.
text
(
textValue
),
matching:
find
.
byType
(
FadeTransition
),
).
first
);
return
opacityWidget
.
opacity
.
value
;
}
Material
_getMaterial
(
WidgetTester
tester
)
{
return
tester
.
firstWidget
<
Material
>(
find
.
descendant
(
of:
find
.
byType
(
BottomNavigationBar
),
matching:
find
.
byType
(
Material
)),
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment