mirror of
https://github.com/flutter/flutter
synced 2024-10-13 03:32:55 +00:00
Tweaked TabBar to provide uniform padding to all tabs in cases where only few tabs contain both icon and text (#80237)
This commit is contained in:
parent
457f513f37
commit
efd3cc5ca7
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue