Commit edcab3c3 authored by Adam Barth's avatar Adam Barth Committed by GitHub

Add TabBar.unselectedLabelColor (#7747)

Our previous behavior of hard-coding the unselected label color to 70% of the
selected color was too restrictive.

Fixes #7738
parent a0dee550
...@@ -108,11 +108,13 @@ class _TabStyle extends AnimatedWidget { ...@@ -108,11 +108,13 @@ class _TabStyle extends AnimatedWidget {
Animation<double> animation, Animation<double> animation,
this.selected, this.selected,
this.labelColor, this.labelColor,
this.unselectedLabelColor,
this.child this.child
}) : super(key: key, animation: animation); }) : super(key: key, animation: animation);
final bool selected; final bool selected;
final Color labelColor; final Color labelColor;
final Color unselectedLabelColor;
final Widget child; final Widget child;
@override @override
...@@ -120,7 +122,7 @@ class _TabStyle extends AnimatedWidget { ...@@ -120,7 +122,7 @@ class _TabStyle extends AnimatedWidget {
final ThemeData themeData = Theme.of(context); final ThemeData themeData = Theme.of(context);
final TextStyle textStyle = themeData.primaryTextTheme.body2; final TextStyle textStyle = themeData.primaryTextTheme.body2;
final Color selectedColor = labelColor ?? themeData.primaryTextTheme.body2.color; final Color selectedColor = labelColor ?? themeData.primaryTextTheme.body2.color;
final Color unselectedColor = selectedColor.withAlpha(0xB2); // 70% alpha final Color unselectedColor = unselectedLabelColor ?? selectedColor.withAlpha(0xB2); // 70% alpha
final Color color = selected final Color color = selected
? Color.lerp(unselectedColor, selectedColor, animation.value) ? Color.lerp(unselectedColor, selectedColor, animation.value)
: Color.lerp(selectedColor, unselectedColor, animation.value); : Color.lerp(selectedColor, unselectedColor, animation.value);
...@@ -325,6 +327,7 @@ class TabBar extends StatefulWidget implements AppBarBottomWidget { ...@@ -325,6 +327,7 @@ class TabBar extends StatefulWidget implements AppBarBottomWidget {
this.isScrollable: false, this.isScrollable: false,
this.indicatorColor, this.indicatorColor,
this.labelColor, this.labelColor,
this.unselectedLabelColor,
}) : super(key: key) { }) : super(key: key) {
assert(tabs != null && tabs.length > 1); assert(tabs != null && tabs.length > 1);
assert(isScrollable != null); assert(isScrollable != null);
...@@ -350,11 +353,21 @@ class TabBar extends StatefulWidget implements AppBarBottomWidget { ...@@ -350,11 +353,21 @@ class TabBar extends StatefulWidget implements AppBarBottomWidget {
/// is null then the value of the Theme's indicatorColor property is used. /// is null then the value of the Theme's indicatorColor property is used.
final Color indicatorColor; final Color indicatorColor;
/// The color of selected tab labels. Unselected tab labels are rendered /// The color of selected tab labels.
/// with the same color rendered at 70% opacity. If this parameter is null then ///
/// the color of the theme's body2 text color is used. /// Unselected tab labels are rendered with the same color rendered at 70%
/// opacity unless [unselectedLabelColor] is non-null.
///
/// If this parameter is null then the color of the theme's body2 text color
/// is used.
final Color labelColor; final Color labelColor;
/// The color of unselected tab labels.
///
/// If this property is null, Unselected tab labels are rendered with the
/// [labelColor] rendered at 70% opacity.
final Color unselectedLabelColor;
@override @override
double get bottomHeight { double get bottomHeight {
for (Widget widget in tabs) { for (Widget widget in tabs) {
...@@ -518,12 +531,14 @@ class _TabBarState extends State<TabBar> { ...@@ -518,12 +531,14 @@ class _TabBarState extends State<TabBar> {
animation: _changeAnimation, animation: _changeAnimation,
selected: true, selected: true,
labelColor: config.labelColor, labelColor: config.labelColor,
unselectedLabelColor: config.unselectedLabelColor,
child: wrappedTabs[_currentIndex], child: wrappedTabs[_currentIndex],
); );
wrappedTabs[previousIndex] = new _TabStyle( wrappedTabs[previousIndex] = new _TabStyle(
animation: _changeAnimation, animation: _changeAnimation,
selected: false, selected: false,
labelColor: config.labelColor, labelColor: config.labelColor,
unselectedLabelColor: config.unselectedLabelColor,
child: wrappedTabs[previousIndex], child: wrappedTabs[previousIndex],
); );
} else { } else {
...@@ -531,6 +546,7 @@ class _TabBarState extends State<TabBar> { ...@@ -531,6 +546,7 @@ class _TabBarState extends State<TabBar> {
animation: kAlwaysCompleteAnimation, animation: kAlwaysCompleteAnimation,
selected: true, selected: true,
labelColor: config.labelColor, labelColor: config.labelColor,
unselectedLabelColor: config.unselectedLabelColor,
child: wrappedTabs[_currentIndex], child: wrappedTabs[_currentIndex],
); );
} }
...@@ -556,6 +572,7 @@ class _TabBarState extends State<TabBar> { ...@@ -556,6 +572,7 @@ class _TabBarState extends State<TabBar> {
animation: kAlwaysCompleteAnimation, animation: kAlwaysCompleteAnimation,
selected: false, selected: false,
labelColor: config.labelColor, labelColor: config.labelColor,
unselectedLabelColor: config.unselectedLabelColor,
child: new _TabLabelBar( child: new _TabLabelBar(
onPerformLayout: _saveTabOffsets, onPerformLayout: _saveTabOffsets,
children: wrappedTabs, children: wrappedTabs,
......
...@@ -545,4 +545,41 @@ void main() { ...@@ -545,4 +545,41 @@ void main() {
await tester.pump(const Duration(seconds: 1)); // finish the scroll animation await tester.pump(const Duration(seconds: 1)); // finish the scroll animation
}); });
testWidgets('TabBar unselectedLabelColor control test', (WidgetTester tester) async {
TabController controller = new TabController(
vsync: const TestVSync(),
length: 2,
);
Color firstColor;
Color secondColor;
await tester.pumpWidget(
new Material(
child: new TabBar(
controller: controller,
labelColor: Colors.green[500],
unselectedLabelColor: Colors.blue[500],
tabs: <Widget>[
new Builder(
builder: (BuildContext context) {
firstColor = IconTheme.of(context).color;
return new Text('First');
}
),
new Builder(
builder: (BuildContext context) {
secondColor = IconTheme.of(context).color;
return new Text('Second');
}
),
],
),
),
);
expect(firstColor, equals(Colors.green[500]));
expect(secondColor, equals(Colors.blue[500]));
});
} }
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