Fix divider width in scrollable TabBar
for Material 3 and add dividerHeight
parameter (#123127)
Fix divider width in scrollable `TabBar` for Material 3 and add `dividerHeight` parameter
This commit is contained in:
parent
d6287cc417
commit
3512c2cd76
@ -20,6 +20,9 @@ class _${blockName}PrimaryDefaultsM3 extends TabBarTheme {
|
|||||||
late final ColorScheme _colors = Theme.of(context).colorScheme;
|
late final ColorScheme _colors = Theme.of(context).colorScheme;
|
||||||
late final TextTheme _textTheme = Theme.of(context).textTheme;
|
late final TextTheme _textTheme = Theme.of(context).textTheme;
|
||||||
|
|
||||||
|
@override
|
||||||
|
double? get dividerHeight => ${tokens['md.comp.primary-navigation-tab.divider.height']};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Color? get dividerColor => ${componentColor("md.comp.primary-navigation-tab.divider")};
|
Color? get dividerColor => ${componentColor("md.comp.primary-navigation-tab.divider")};
|
||||||
|
|
||||||
@ -81,6 +84,9 @@ class _${blockName}SecondaryDefaultsM3 extends TabBarTheme {
|
|||||||
@override
|
@override
|
||||||
Color? get dividerColor => ${componentColor("md.comp.secondary-navigation-tab.divider")};
|
Color? get dividerColor => ${componentColor("md.comp.secondary-navigation-tab.divider")};
|
||||||
|
|
||||||
|
@override
|
||||||
|
double? get dividerHeight => ${tokens['md.comp.primary-navigation-tab.divider.height']};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Color? get indicatorColor => ${componentColor("md.comp.primary-navigation-tab.active-indicator")};
|
Color? get indicatorColor => ${componentColor("md.comp.primary-navigation-tab.active-indicator")};
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ class TabBarTheme with Diagnosticable {
|
|||||||
this.indicatorColor,
|
this.indicatorColor,
|
||||||
this.indicatorSize,
|
this.indicatorSize,
|
||||||
this.dividerColor,
|
this.dividerColor,
|
||||||
|
this.dividerHeight,
|
||||||
this.labelColor,
|
this.labelColor,
|
||||||
this.labelPadding,
|
this.labelPadding,
|
||||||
this.labelStyle,
|
this.labelStyle,
|
||||||
@ -54,6 +55,9 @@ class TabBarTheme with Diagnosticable {
|
|||||||
/// Overrides the default value for [TabBar.dividerColor].
|
/// Overrides the default value for [TabBar.dividerColor].
|
||||||
final Color? dividerColor;
|
final Color? dividerColor;
|
||||||
|
|
||||||
|
/// Overrides the default value for [TabBar.dividerHeight].
|
||||||
|
final double? dividerHeight;
|
||||||
|
|
||||||
/// Overrides the default value for [TabBar.labelColor].
|
/// Overrides the default value for [TabBar.labelColor].
|
||||||
///
|
///
|
||||||
/// If [labelColor] is a [MaterialStateColor], then the effective color will
|
/// If [labelColor] is a [MaterialStateColor], then the effective color will
|
||||||
@ -97,6 +101,7 @@ class TabBarTheme with Diagnosticable {
|
|||||||
Color? indicatorColor,
|
Color? indicatorColor,
|
||||||
TabBarIndicatorSize? indicatorSize,
|
TabBarIndicatorSize? indicatorSize,
|
||||||
Color? dividerColor,
|
Color? dividerColor,
|
||||||
|
double? dividerHeight,
|
||||||
Color? labelColor,
|
Color? labelColor,
|
||||||
EdgeInsetsGeometry? labelPadding,
|
EdgeInsetsGeometry? labelPadding,
|
||||||
TextStyle? labelStyle,
|
TextStyle? labelStyle,
|
||||||
@ -111,6 +116,7 @@ class TabBarTheme with Diagnosticable {
|
|||||||
indicatorColor: indicatorColor ?? this.indicatorColor,
|
indicatorColor: indicatorColor ?? this.indicatorColor,
|
||||||
indicatorSize: indicatorSize ?? this.indicatorSize,
|
indicatorSize: indicatorSize ?? this.indicatorSize,
|
||||||
dividerColor: dividerColor ?? this.dividerColor,
|
dividerColor: dividerColor ?? this.dividerColor,
|
||||||
|
dividerHeight: dividerHeight ?? this.dividerHeight,
|
||||||
labelColor: labelColor ?? this.labelColor,
|
labelColor: labelColor ?? this.labelColor,
|
||||||
labelPadding: labelPadding ?? this.labelPadding,
|
labelPadding: labelPadding ?? this.labelPadding,
|
||||||
labelStyle: labelStyle ?? this.labelStyle,
|
labelStyle: labelStyle ?? this.labelStyle,
|
||||||
@ -141,6 +147,7 @@ class TabBarTheme with Diagnosticable {
|
|||||||
indicatorColor: Color.lerp(a.indicatorColor, b.indicatorColor, t),
|
indicatorColor: Color.lerp(a.indicatorColor, b.indicatorColor, t),
|
||||||
indicatorSize: t < 0.5 ? a.indicatorSize : b.indicatorSize,
|
indicatorSize: t < 0.5 ? a.indicatorSize : b.indicatorSize,
|
||||||
dividerColor: Color.lerp(a.dividerColor, b.dividerColor, t),
|
dividerColor: Color.lerp(a.dividerColor, b.dividerColor, t),
|
||||||
|
dividerHeight: t < 0.5 ? a.dividerHeight : b.dividerHeight,
|
||||||
labelColor: Color.lerp(a.labelColor, b.labelColor, t),
|
labelColor: Color.lerp(a.labelColor, b.labelColor, t),
|
||||||
labelPadding: EdgeInsetsGeometry.lerp(a.labelPadding, b.labelPadding, t),
|
labelPadding: EdgeInsetsGeometry.lerp(a.labelPadding, b.labelPadding, t),
|
||||||
labelStyle: TextStyle.lerp(a.labelStyle, b.labelStyle, t),
|
labelStyle: TextStyle.lerp(a.labelStyle, b.labelStyle, t),
|
||||||
@ -158,6 +165,7 @@ class TabBarTheme with Diagnosticable {
|
|||||||
indicatorColor,
|
indicatorColor,
|
||||||
indicatorSize,
|
indicatorSize,
|
||||||
dividerColor,
|
dividerColor,
|
||||||
|
dividerHeight,
|
||||||
labelColor,
|
labelColor,
|
||||||
labelPadding,
|
labelPadding,
|
||||||
labelStyle,
|
labelStyle,
|
||||||
@ -181,6 +189,7 @@ class TabBarTheme with Diagnosticable {
|
|||||||
&& other.indicatorColor == indicatorColor
|
&& other.indicatorColor == indicatorColor
|
||||||
&& other.indicatorSize == indicatorSize
|
&& other.indicatorSize == indicatorSize
|
||||||
&& other.dividerColor == dividerColor
|
&& other.dividerColor == dividerColor
|
||||||
|
&& other.dividerHeight == dividerHeight
|
||||||
&& other.labelColor == labelColor
|
&& other.labelColor == labelColor
|
||||||
&& other.labelPadding == labelPadding
|
&& other.labelPadding == labelPadding
|
||||||
&& other.labelStyle == labelStyle
|
&& other.labelStyle == labelStyle
|
||||||
|
@ -109,7 +109,8 @@ class _UnderlinePainter extends BoxPainter {
|
|||||||
if (borderRadius != null) {
|
if (borderRadius != null) {
|
||||||
paint = Paint()..color = decoration.borderSide.color;
|
paint = Paint()..color = decoration.borderSide.color;
|
||||||
final Rect indicator = decoration._indicatorRectFor(rect, textDirection)
|
final Rect indicator = decoration._indicatorRectFor(rect, textDirection)
|
||||||
.inflate(decoration.borderSide.width / 4.0);
|
.inflate(decoration.borderSide.width / 4.0)
|
||||||
|
.shift(Offset(0.0, -decoration.borderSide.width / 2.0));
|
||||||
final RRect rrect = RRect.fromRectAndCorners(
|
final RRect rrect = RRect.fromRectAndCorners(
|
||||||
indicator,
|
indicator,
|
||||||
topLeft: borderRadius!.topLeft,
|
topLeft: borderRadius!.topLeft,
|
||||||
|
@ -15,6 +15,7 @@ import 'color_scheme.dart';
|
|||||||
import 'colors.dart';
|
import 'colors.dart';
|
||||||
import 'constants.dart';
|
import 'constants.dart';
|
||||||
import 'debug.dart';
|
import 'debug.dart';
|
||||||
|
import 'divider.dart';
|
||||||
import 'ink_well.dart';
|
import 'ink_well.dart';
|
||||||
import 'material.dart';
|
import 'material.dart';
|
||||||
import 'material_localizations.dart';
|
import 'material_localizations.dart';
|
||||||
@ -360,7 +361,6 @@ class _IndicatorPainter extends CustomPainter {
|
|||||||
required _IndicatorPainter? old,
|
required _IndicatorPainter? old,
|
||||||
required this.indicatorPadding,
|
required this.indicatorPadding,
|
||||||
required this.labelPaddings,
|
required this.labelPaddings,
|
||||||
this.dividerColor,
|
|
||||||
}) : super(repaint: controller.animation) {
|
}) : super(repaint: controller.animation) {
|
||||||
if (old != null) {
|
if (old != null) {
|
||||||
saveTabOffsets(old._currentTabOffsets, old._currentTextDirection);
|
saveTabOffsets(old._currentTabOffsets, old._currentTextDirection);
|
||||||
@ -372,7 +372,6 @@ class _IndicatorPainter extends CustomPainter {
|
|||||||
final TabBarIndicatorSize? indicatorSize;
|
final TabBarIndicatorSize? indicatorSize;
|
||||||
final EdgeInsetsGeometry indicatorPadding;
|
final EdgeInsetsGeometry indicatorPadding;
|
||||||
final List<GlobalKey> tabKeys;
|
final List<GlobalKey> tabKeys;
|
||||||
final Color? dividerColor;
|
|
||||||
final List<EdgeInsetsGeometry> labelPaddings;
|
final List<EdgeInsetsGeometry> labelPaddings;
|
||||||
|
|
||||||
// _currentTabOffsets and _currentTextDirection are set each time TabBar
|
// _currentTabOffsets and _currentTextDirection are set each time TabBar
|
||||||
@ -465,10 +464,6 @@ class _IndicatorPainter extends CustomPainter {
|
|||||||
size: _currentRect!.size,
|
size: _currentRect!.size,
|
||||||
textDirection: _currentTextDirection,
|
textDirection: _currentTextDirection,
|
||||||
);
|
);
|
||||||
if (dividerColor != null) {
|
|
||||||
final Paint dividerPaint = Paint()..color = dividerColor!..strokeWidth = 1;
|
|
||||||
canvas.drawLine(Offset(0, size.height), Offset(size.width, size.height), dividerPaint);
|
|
||||||
}
|
|
||||||
_painter!.paint(canvas, _currentRect!.topLeft, configuration);
|
_painter!.paint(canvas, _currentRect!.topLeft, configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,6 +677,7 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
|
|||||||
this.indicator,
|
this.indicator,
|
||||||
this.indicatorSize,
|
this.indicatorSize,
|
||||||
this.dividerColor,
|
this.dividerColor,
|
||||||
|
this.dividerHeight,
|
||||||
this.labelColor,
|
this.labelColor,
|
||||||
this.labelStyle,
|
this.labelStyle,
|
||||||
this.labelPadding,
|
this.labelPadding,
|
||||||
@ -731,6 +727,7 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
|
|||||||
this.indicator,
|
this.indicator,
|
||||||
this.indicatorSize,
|
this.indicatorSize,
|
||||||
this.dividerColor,
|
this.dividerColor,
|
||||||
|
this.dividerHeight,
|
||||||
this.labelColor,
|
this.labelColor,
|
||||||
this.labelStyle,
|
this.labelStyle,
|
||||||
this.labelPadding,
|
this.labelPadding,
|
||||||
@ -849,6 +846,13 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
|
|||||||
/// [ColorScheme.surfaceVariant] will be used, otherwise divider will not be drawn.
|
/// [ColorScheme.surfaceVariant] will be used, otherwise divider will not be drawn.
|
||||||
final Color? dividerColor;
|
final Color? dividerColor;
|
||||||
|
|
||||||
|
/// The height of the divider.
|
||||||
|
///
|
||||||
|
/// If null and [ThemeData.useMaterial3] is true, [TabBarTheme.dividerHeight]
|
||||||
|
/// is used. If that is null and [ThemeData.useMaterial3] is true, 1.0 will be used.
|
||||||
|
/// Otherwise divider will not be drawn.
|
||||||
|
final double? dividerHeight;
|
||||||
|
|
||||||
/// The color of selected tab labels.
|
/// The color of selected tab labels.
|
||||||
///
|
///
|
||||||
/// If null, then [TabBarTheme.labelColor] is used. If that is also null and
|
/// If null, then [TabBarTheme.labelColor] is used. If that is also null and
|
||||||
@ -1096,7 +1100,7 @@ class _TabBarState extends State<TabBar> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Decoration _getIndicator() {
|
Decoration _getIndicator(TabBarIndicatorSize indicatorSize) {
|
||||||
final ThemeData theme = Theme.of(context);
|
final ThemeData theme = Theme.of(context);
|
||||||
final TabBarTheme tabBarTheme = TabBarTheme.of(context);
|
final TabBarTheme tabBarTheme = TabBarTheme.of(context);
|
||||||
|
|
||||||
@ -1130,17 +1134,24 @@ class _TabBarState extends State<TabBar> {
|
|||||||
color = Colors.white;
|
color = Colors.white;
|
||||||
}
|
}
|
||||||
|
|
||||||
return UnderlineTabIndicator(
|
if (theme.useMaterial3 && widget._isPrimary && indicatorSize == TabBarIndicatorSize.label) {
|
||||||
borderRadius: theme.useMaterial3 && widget._isPrimary
|
return UnderlineTabIndicator(
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(3.0),
|
||||||
|
topRight: Radius.circular(3.0),
|
||||||
|
),
|
||||||
|
borderSide: BorderSide(
|
||||||
// TODO(tahatesser): Make sure this value matches Material 3 Tabs spec
|
// TODO(tahatesser): Make sure this value matches Material 3 Tabs spec
|
||||||
// when `preferredSize`and `indicatorWeight` are updated to support Material 3
|
// when `preferredSize`and `indicatorWeight` are updated to support Material 3
|
||||||
// https://m3.material.io/components/tabs/specs#149a189f-9039-4195-99da-15c205d20e30,
|
// https://m3.material.io/components/tabs/specs#149a189f-9039-4195-99da-15c205d20e30,
|
||||||
// https://github.com/flutter/flutter/issues/116136
|
// https://github.com/flutter/flutter/issues/116136
|
||||||
? const BorderRadius.only(
|
width: widget.indicatorWeight,
|
||||||
topLeft: Radius.circular(3.0),
|
color: color,
|
||||||
topRight: Radius.circular(3.0),
|
),
|
||||||
)
|
);
|
||||||
: null,
|
}
|
||||||
|
|
||||||
|
return UnderlineTabIndicator(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
width: widget.indicatorWeight,
|
width: widget.indicatorWeight,
|
||||||
color: color,
|
color: color,
|
||||||
@ -1185,17 +1196,18 @@ class _TabBarState extends State<TabBar> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _initIndicatorPainter() {
|
void _initIndicatorPainter() {
|
||||||
final ThemeData theme = Theme.of(context);
|
|
||||||
final TabBarTheme tabBarTheme = TabBarTheme.of(context);
|
final TabBarTheme tabBarTheme = TabBarTheme.of(context);
|
||||||
|
final TabBarIndicatorSize indicatorSize = widget.indicatorSize
|
||||||
|
?? tabBarTheme.indicatorSize
|
||||||
|
?? _defaults.indicatorSize!;
|
||||||
|
|
||||||
_indicatorPainter = !_controllerIsValid ? null : _IndicatorPainter(
|
_indicatorPainter = !_controllerIsValid ? null : _IndicatorPainter(
|
||||||
controller: _controller!,
|
controller: _controller!,
|
||||||
indicator: _getIndicator(),
|
indicator: _getIndicator(indicatorSize),
|
||||||
indicatorSize: widget.indicatorSize ?? tabBarTheme.indicatorSize ?? _defaults.indicatorSize!,
|
indicatorSize: indicatorSize,
|
||||||
indicatorPadding: widget.indicatorPadding,
|
indicatorPadding: widget.indicatorPadding,
|
||||||
tabKeys: _tabKeys,
|
tabKeys: _tabKeys,
|
||||||
old: _indicatorPainter,
|
old: _indicatorPainter,
|
||||||
dividerColor: theme.useMaterial3 ? widget.dividerColor ?? tabBarTheme.dividerColor ?? _defaults.dividerColor : null,
|
|
||||||
labelPaddings: _labelPaddings,
|
labelPaddings: _labelPaddings,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1390,6 +1402,7 @@ class _TabBarState extends State<TabBar> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(context);
|
||||||
final TabBarTheme tabBarTheme = TabBarTheme.of(context);
|
final TabBarTheme tabBarTheme = TabBarTheme.of(context);
|
||||||
|
|
||||||
final List<Widget> wrappedTabs = List<Widget>.generate(widget.tabs.length, (int index) {
|
final List<Widget> wrappedTabs = List<Widget>.generate(widget.tabs.length, (int index) {
|
||||||
@ -1535,6 +1548,24 @@ class _TabBarState extends State<TabBar> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (theme.useMaterial3) {
|
||||||
|
tabBar = Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
height: widget.preferredSize.height,
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
child: Divider(
|
||||||
|
height: 0,
|
||||||
|
thickness: widget.dividerHeight ?? tabBarTheme.dividerHeight ?? _defaults.dividerHeight,
|
||||||
|
color: widget.dividerColor ?? tabBarTheme.dividerColor ?? _defaults.dividerColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
tabBar,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return tabBar;
|
return tabBar;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2068,6 +2099,9 @@ class _TabsPrimaryDefaultsM3 extends TabBarTheme {
|
|||||||
late final ColorScheme _colors = Theme.of(context).colorScheme;
|
late final ColorScheme _colors = Theme.of(context).colorScheme;
|
||||||
late final TextTheme _textTheme = Theme.of(context).textTheme;
|
late final TextTheme _textTheme = Theme.of(context).textTheme;
|
||||||
|
|
||||||
|
@override
|
||||||
|
double? get dividerHeight => 1.0;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Color? get dividerColor => _colors.surfaceVariant;
|
Color? get dividerColor => _colors.surfaceVariant;
|
||||||
|
|
||||||
@ -2129,6 +2163,9 @@ class _TabsSecondaryDefaultsM3 extends TabBarTheme {
|
|||||||
@override
|
@override
|
||||||
Color? get dividerColor => _colors.surfaceVariant;
|
Color? get dividerColor => _colors.surfaceVariant;
|
||||||
|
|
||||||
|
@override
|
||||||
|
double? get dividerHeight => 1.0;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Color? get indicatorColor => _colors.primary;
|
Color? get indicatorColor => _colors.primary;
|
||||||
|
|
||||||
|
@ -126,27 +126,30 @@ void main() {
|
|||||||
final Rect tabTwoRect = tester.getRect(find.byKey(_sizedTabs[1].key!));
|
final Rect tabTwoRect = tester.getRect(find.byKey(_sizedTabs[1].key!));
|
||||||
|
|
||||||
// Verify tabOne coordinates.
|
// Verify tabOne coordinates.
|
||||||
expect(tabOneRect.left, equals(kTabLabelPadding.left));
|
final double tabOneLeft = (tabBar.width
|
||||||
|
- (tabOneRect.width + tabTwoRect.width) - kTabLabelPadding.horizontal) / 2;
|
||||||
|
expect(tabOneRect.left, equals(tabOneLeft));
|
||||||
expect(tabOneRect.top, equals(kTabLabelPadding.top));
|
expect(tabOneRect.top, equals(kTabLabelPadding.top));
|
||||||
expect(tabOneRect.bottom, equals(tabBar.bottom - kTabLabelPadding.bottom - indicatorWeight));
|
expect(tabOneRect.bottom, equals(tabBar.bottom - kTabLabelPadding.bottom - indicatorWeight));
|
||||||
|
|
||||||
// Verify tabTwo coordinates.
|
// Verify tabTwo coordinates.
|
||||||
expect(tabTwoRect.right, equals(tabBar.width - kTabLabelPadding.right));
|
final double tabTwoRight = tabBar.width
|
||||||
|
- (tabBar.width - (tabOneRect.width + tabTwoRect.width) - kTabLabelPadding.horizontal) / 2;
|
||||||
|
expect(tabTwoRect.right, equals(tabTwoRight));
|
||||||
expect(tabTwoRect.top, equals(kTabLabelPadding.top));
|
expect(tabTwoRect.top, equals(kTabLabelPadding.top));
|
||||||
expect(tabTwoRect.bottom, equals(tabBar.bottom - kTabLabelPadding.bottom - indicatorWeight));
|
expect(tabTwoRect.bottom, equals(tabBar.bottom - kTabLabelPadding.bottom - indicatorWeight));
|
||||||
|
|
||||||
// Verify tabOne and tabTwo is separated by right padding of tabOne and left padding of tabTwo.
|
// Verify tabOne and tabTwo is separated by right padding of tabOne and left padding of tabTwo.
|
||||||
expect(tabOneRect.right, equals(tabTwoRect.left - kTabLabelPadding.left - kTabLabelPadding.right));
|
expect(tabOneRect.right, equals(tabTwoRect.left - kTabLabelPadding.left - kTabLabelPadding.right));
|
||||||
|
|
||||||
// Verify divider color and indicator color.
|
// Test default divider color.
|
||||||
|
final Divider divider = tester.widget<Divider>(find.byType(Divider));
|
||||||
|
expect(divider.color, equals(theme.colorScheme.surfaceVariant));
|
||||||
|
expect(divider.thickness, 1.0);
|
||||||
|
|
||||||
|
// Test default indicator color.
|
||||||
final RenderBox tabBarBox = tester.firstRenderObject<RenderBox>(find.byType(TabBar));
|
final RenderBox tabBarBox = tester.firstRenderObject<RenderBox>(find.byType(TabBar));
|
||||||
expect(
|
expect(tabBarBox, paints..rrect(color: theme.colorScheme.primary));
|
||||||
tabBarBox,
|
|
||||||
paints
|
|
||||||
..line(color: theme.colorScheme.surfaceVariant)
|
|
||||||
// Indicator is a rrect in the primary tab bar.
|
|
||||||
..rrect(color: theme.colorScheme.primary),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Tab bar defaults (secondary)', (WidgetTester tester) async {
|
testWidgets('Tab bar defaults (secondary)', (WidgetTester tester) async {
|
||||||
@ -177,27 +180,30 @@ void main() {
|
|||||||
final Rect tabTwoRect = tester.getRect(find.byKey(_sizedTabs[1].key!));
|
final Rect tabTwoRect = tester.getRect(find.byKey(_sizedTabs[1].key!));
|
||||||
|
|
||||||
// Verify tabOne coordinates.
|
// Verify tabOne coordinates.
|
||||||
expect(tabOneRect.left, equals(kTabLabelPadding.left));
|
final double tabOneLeft = (tabBar.width
|
||||||
|
- (tabOneRect.width + tabTwoRect.width) - kTabLabelPadding.horizontal) / 2;
|
||||||
|
expect(tabOneRect.left, equals(tabOneLeft));
|
||||||
expect(tabOneRect.top, equals(kTabLabelPadding.top));
|
expect(tabOneRect.top, equals(kTabLabelPadding.top));
|
||||||
expect(tabOneRect.bottom, equals(tabBar.bottom - kTabLabelPadding.bottom - indicatorWeight));
|
expect(tabOneRect.bottom, equals(tabBar.bottom - kTabLabelPadding.bottom - indicatorWeight));
|
||||||
|
|
||||||
// Verify tabTwo coordinates.
|
// Verify tabTwo coordinates.
|
||||||
expect(tabTwoRect.right, equals(tabBar.width - kTabLabelPadding.right));
|
final double tabTwoRight = tabBar.width
|
||||||
|
- (tabBar.width - (tabOneRect.width + tabTwoRect.width) - kTabLabelPadding.horizontal) / 2;
|
||||||
|
expect(tabTwoRect.right, equals(tabTwoRight));
|
||||||
expect(tabTwoRect.top, equals(kTabLabelPadding.top));
|
expect(tabTwoRect.top, equals(kTabLabelPadding.top));
|
||||||
expect(tabTwoRect.bottom, equals(tabBar.bottom - kTabLabelPadding.bottom - indicatorWeight));
|
expect(tabTwoRect.bottom, equals(tabBar.bottom - kTabLabelPadding.bottom - indicatorWeight));
|
||||||
|
|
||||||
// Verify tabOne and tabTwo is separated by right padding of tabOne and left padding of tabTwo.
|
// Verify tabOne and tabTwo is separated by right padding of tabOne and left padding of tabTwo.
|
||||||
expect(tabOneRect.right, equals(tabTwoRect.left - kTabLabelPadding.left - kTabLabelPadding.right));
|
expect(tabOneRect.right, equals(tabTwoRect.left - kTabLabelPadding.left - kTabLabelPadding.right));
|
||||||
|
|
||||||
// Verify divider color and indicator color.
|
// Test default divider color.
|
||||||
|
final Divider divider = tester.widget<Divider>(find.byType(Divider));
|
||||||
|
expect(divider.color, equals(theme.colorScheme.surfaceVariant));
|
||||||
|
expect(divider.thickness, 1.0);
|
||||||
|
|
||||||
|
// Test default indicator color.
|
||||||
final RenderBox tabBarBox = tester.firstRenderObject<RenderBox>(find.byType(TabBar));
|
final RenderBox tabBarBox = tester.firstRenderObject<RenderBox>(find.byType(TabBar));
|
||||||
expect(
|
expect(tabBarBox, paints..line(color: theme.colorScheme.primary));
|
||||||
tabBarBox,
|
|
||||||
paints
|
|
||||||
..line(color: theme.colorScheme.surfaceVariant)
|
|
||||||
// Indicator is a line in the secondary tab bar.
|
|
||||||
..line(color: theme.colorScheme.primary),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Tab bar theme overrides label color (selected)', (WidgetTester tester) async {
|
testWidgets('Tab bar theme overrides label color (selected)', (WidgetTester tester) async {
|
||||||
@ -378,21 +384,21 @@ void main() {
|
|||||||
expect(iconRenderObject.text.style!.color, equals(unselectedLabelColor));
|
expect(iconRenderObject.text.style!.color, equals(unselectedLabelColor));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Tab bar default tab indicator size', (WidgetTester tester) async {
|
testWidgets('Tab bar default tab indicator size (primary)', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(buildTabBar(useMaterial3: true, isScrollable: true));
|
await tester.pumpWidget(buildTabBar(useMaterial3: true, isScrollable: true));
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
find.byKey(_painterKey),
|
find.byKey(_painterKey),
|
||||||
matchesGoldenFile('tab_bar.default.tab_indicator_size.png'),
|
matchesGoldenFile('tab_bar_primary.default.tab_indicator_size.png'),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Tab bar default tab indicator size', (WidgetTester tester) async {
|
testWidgets('Tab bar default tab indicator size (secondary)', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(buildTabBar(useMaterial3: true, isScrollable: true));
|
await tester.pumpWidget(buildTabBar(secondaryTabBar: true, useMaterial3: true, isScrollable: true));
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
find.byKey(_painterKey),
|
find.byKey(_painterKey),
|
||||||
matchesGoldenFile('tab_bar.default.tab_indicator_size.png'),
|
matchesGoldenFile('tab_bar_secondary.default.tab_indicator_size.png'),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -464,6 +470,74 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('TabBar divider can use TabBarTheme.dividerColor & TabBarTheme.dividerHeight', (WidgetTester tester) async {
|
||||||
|
const Color dividerColor = Colors.yellow;
|
||||||
|
const double dividerHeight = 10.0;
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
theme: ThemeData(
|
||||||
|
useMaterial3: true,
|
||||||
|
tabBarTheme: const TabBarTheme(
|
||||||
|
dividerColor: dividerColor,
|
||||||
|
dividerHeight: dividerHeight,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
home: Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
bottom: TabBar(
|
||||||
|
controller: TabController(length: 3, vsync: const TestVSync()),
|
||||||
|
tabs: const <Widget>[
|
||||||
|
Tab(text: 'Tab 1'),
|
||||||
|
Tab(text: 'Tab 2'),
|
||||||
|
Tab(text: 'Tab 3'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final Divider divider = tester.widget<Divider>(find.byType(Divider));
|
||||||
|
expect(divider.color, equals(dividerColor));
|
||||||
|
expect(divider.thickness, dividerHeight);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('dividerColor & dividerHeight overrides TabBarTheme.dividerColor', (WidgetTester tester) async {
|
||||||
|
const Color dividerColor = Colors.amber;
|
||||||
|
const double dividerHeight = 8.0;
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
theme: ThemeData(
|
||||||
|
useMaterial3: true,
|
||||||
|
tabBarTheme: const TabBarTheme(
|
||||||
|
dividerColor: Colors.pink,
|
||||||
|
dividerHeight: 5.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
home: Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
bottom: TabBar(
|
||||||
|
dividerColor: dividerColor,
|
||||||
|
dividerHeight: dividerHeight,
|
||||||
|
controller: TabController(length: 3, vsync: const TestVSync()),
|
||||||
|
tabs: const <Widget>[
|
||||||
|
Tab(text: 'Tab 1'),
|
||||||
|
Tab(text: 'Tab 2'),
|
||||||
|
Tab(text: 'Tab 3'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final Divider divider = tester.widget<Divider>(find.byType(Divider));
|
||||||
|
expect(divider.color, equals(dividerColor));
|
||||||
|
expect(divider.thickness, dividerHeight);
|
||||||
|
});
|
||||||
|
|
||||||
group('Material 2', () {
|
group('Material 2', () {
|
||||||
// Tests that are only relevant for Material 2. Once ThemeData.useMaterial3
|
// Tests that are only relevant for Material 2. Once ThemeData.useMaterial3
|
||||||
// is turned on by default, these tests can be removed.
|
// is turned on by default, these tests can be removed.
|
||||||
|
@ -5778,36 +5778,6 @@ void main() {
|
|||||||
labelColor.withAlpha(0xB2) // 70% alpha,
|
labelColor.withAlpha(0xB2) // 70% alpha,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Material3 - TabBar inherits the dividerColor of TabBarTheme', (WidgetTester tester) async {
|
|
||||||
const Color dividerColor = Colors.yellow;
|
|
||||||
|
|
||||||
await tester.pumpWidget(
|
|
||||||
MaterialApp(
|
|
||||||
theme: ThemeData(
|
|
||||||
useMaterial3: true,
|
|
||||||
tabBarTheme: const TabBarTheme(dividerColor: dividerColor),
|
|
||||||
),
|
|
||||||
home: Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
bottom: TabBar(
|
|
||||||
controller: TabController(length: 3, vsync: const TestVSync()),
|
|
||||||
tabs: const <Widget>[
|
|
||||||
Tab(text: 'Tab 1'),
|
|
||||||
Tab(text: 'Tab 2'),
|
|
||||||
Tab(text: 'Tab 3'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Test painter's divider color.
|
|
||||||
final CustomPaint paint = tester.widget<CustomPaint>(find.byType(CustomPaint).last);
|
|
||||||
// ignore: avoid_dynamic_calls
|
|
||||||
expect((paint.painter as dynamic).dividerColor, dividerColor);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user