Unverified Commit efd3cc5c authored by Chinmoy's avatar Chinmoy Committed by GitHub

Tweaked TabBar to provide uniform padding to all tabs in cases where only few...

Tweaked TabBar to provide uniform padding to all tabs in cases where only few tabs contain both icon and text (#80237)
parent 457f513f
......@@ -45,6 +45,10 @@ class TabBarTheme with Diagnosticable {
final Color? labelColor;
/// Default value for [TabBar.labelPadding].
///
/// If there are few tabs with both icon and text and few
/// tabs with only icon or text, this padding is vertically
/// adjusted to provide uniform padding to all tabs.
final EdgeInsetsGeometry? labelPadding;
/// Default value for [TabBar.labelStyle].
......
......@@ -833,6 +833,10 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
/// The padding added to each of the tab labels.
///
/// If there are few tabs with both icon and text and few
/// tabs with only icon or text, this padding is vertically
/// adjusted to provide uniform padding to all tabs.
///
/// If this property is null, then kTabLabelPadding is used.
final EdgeInsetsGeometry? labelPadding;
......@@ -910,6 +914,21 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
return Size.fromHeight(maxHeight + indicatorWeight);
}
/// Returns whether the [TabBar] contains a tab with both text and icon.
///
/// [TabBar] uses this to give uniform padding to all tabs in cases where
/// there are some tabs with both text and icon and some which contain only
/// text or icon.
bool get tabHasTextAndIcon {
for (final Widget item in tabs) {
if (item is PreferredSizeWidget) {
if (item.preferredSize.height == _kTextAndIconTabHeight)
return true;
}
}
return false;
}
@override
_TabBarState createState() => _TabBarState();
}
......@@ -1168,19 +1187,33 @@ class _TabBarState extends State<TabBar> {
final TabBarTheme tabBarTheme = TabBarTheme.of(context);
final List<Widget> wrappedTabs = <Widget>[
for (int i = 0; i < widget.tabs.length; i += 1)
Center(
final List<Widget> wrappedTabs = List<Widget>.generate(widget.tabs.length, (int index) {
const double verticalAdjustment = (_kTextAndIconTabHeight - _kTabHeight)/2.0;
EdgeInsetsGeometry? adjustedPadding;
if (widget.tabs[index] is PreferredSizeWidget) {
final PreferredSizeWidget tab = widget.tabs[index] as PreferredSizeWidget;
if (widget.tabHasTextAndIcon && tab.preferredSize.height == _kTabHeight) {
if (widget.labelPadding != null || tabBarTheme.labelPadding != null) {
adjustedPadding = (widget.labelPadding ?? tabBarTheme.labelPadding!).add(const EdgeInsets.symmetric(vertical: verticalAdjustment));
}
else {
adjustedPadding = const EdgeInsets.symmetric(vertical: verticalAdjustment, horizontal: 16.0);
}
}
}
return Center(
heightFactor: 1.0,
child: Padding(
padding: widget.labelPadding ?? tabBarTheme.labelPadding ?? kTabLabelPadding,
padding: adjustedPadding ?? widget.labelPadding ?? tabBarTheme.labelPadding ?? kTabLabelPadding,
child: KeyedSubtree(
key: _tabKeys[i],
child: widget.tabs[i],
),
key: _tabKeys[index],
child: widget.tabs[index],
),
),
];
);
});
// If the controller was provided by DefaultTabController and we're part
// of a Hero (typically the AppBar), then we will not be able to find the
......
......@@ -3532,6 +3532,102 @@ void main() {
expect(tabBar.preferredSize, const Size.fromHeight(48.0));
});
testWidgets('Tabs are given uniform padding in case of few tabs having both text and icon', (WidgetTester tester) async {
const EdgeInsetsGeometry expectedPaddingAdjusted = EdgeInsets.symmetric(vertical: 13.0, horizontal: 16.0);
const EdgeInsetsGeometry expectedPaddingDefault = EdgeInsets.symmetric(vertical: 0.0, horizontal: 16.0);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
appBar: AppBar(
bottom: TabBar(
controller: TabController(length: 3, vsync: const TestVSync()),
tabs: const <Widget>[
Tab(text: 'Tab 1', icon: Icon(Icons.plus_one)),
Tab(text: 'Tab 2'),
Tab(text: 'Tab 3'),
],
),
),
),
),
);
final Padding tabOne = tester.widget<Padding>(find.widgetWithText(Padding, 'Tab 1').first);
final Padding tabTwo = tester.widget<Padding>(find.widgetWithText(Padding, 'Tab 2').first);
final Padding tabThree = tester.widget<Padding>(find.widgetWithText(Padding, 'Tab 3').first);
expect(tabOne.padding, expectedPaddingDefault);
expect(tabTwo.padding, expectedPaddingAdjusted);
expect(tabThree.padding, expectedPaddingAdjusted);
});
testWidgets('Tabs are given uniform padding when labelPadding is given', (WidgetTester tester) async {
const EdgeInsetsGeometry labelPadding = EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0);
const EdgeInsetsGeometry expectedPaddingAdjusted = EdgeInsets.symmetric(vertical: 23.0, horizontal: 20.0);
const EdgeInsetsGeometry expectedPaddingDefault = EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
appBar: AppBar(
bottom: TabBar(
labelPadding: labelPadding,
controller: TabController(length: 3, vsync: const TestVSync()),
tabs: const <Widget>[
Tab(text: 'Tab 1', icon: Icon(Icons.plus_one)),
Tab(text: 'Tab 2'),
Tab(text: 'Tab 3'),
],
),
),
),
),
);
final Padding tabOne = tester.widget<Padding>(find.widgetWithText(Padding, 'Tab 1').first);
final Padding tabTwo = tester.widget<Padding>(find.widgetWithText(Padding, 'Tab 2').first);
final Padding tabThree = tester.widget<Padding>(find.widgetWithText(Padding, 'Tab 3').first);
expect(tabOne.padding, expectedPaddingDefault);
expect(tabTwo.padding, expectedPaddingAdjusted);
expect(tabThree.padding, expectedPaddingAdjusted);
});
testWidgets('Tabs are given uniform padding TabBarTheme.labelPadding is given', (WidgetTester tester) async {
const EdgeInsetsGeometry labelPadding = EdgeInsets.symmetric(vertical: 15.0, horizontal: 20);
const EdgeInsetsGeometry expectedPaddingAdjusted = EdgeInsets.symmetric(vertical: 28.0, horizontal: 20.0);
const EdgeInsetsGeometry expectedPaddingDefault = EdgeInsets.symmetric(vertical: 15.0, horizontal: 20.0);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
tabBarTheme: const TabBarTheme(labelPadding: labelPadding),
),
home: Scaffold(
appBar: AppBar(
bottom: TabBar(
controller: TabController(length: 3, vsync: const TestVSync()),
tabs: const <Widget>[
Tab(text: 'Tab 1', icon: Icon(Icons.plus_one)),
Tab(text: 'Tab 2'),
Tab(text: 'Tab 3'),
],
),
),
),
),
);
final Padding tabOne = tester.widget<Padding>(find.widgetWithText(Padding, 'Tab 1').first);
final Padding tabTwo = tester.widget<Padding>(find.widgetWithText(Padding, 'Tab 2').first);
final Padding tabThree = tester.widget<Padding>(find.widgetWithText(Padding, 'Tab 3').first);
expect(tabOne.padding, expectedPaddingDefault);
expect(tabTwo.padding, expectedPaddingAdjusted);
expect(tabThree.padding, expectedPaddingAdjusted);
});
}
class KeepAliveInk extends StatefulWidget {
......
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