This is the way i tried to do it, but i obviously need the paddings to be calculated somehow. I'm thinking in a worst case scenario creating some sort of function that calculates all that, but can i select elements and get values?
This is roughly how i want them to look like (space between should vary in accordance to screen sizes) https://i.imgur.com/huhC9vn.png
I'm also thinking maybe some screens might not be able to fit it since the emulated one is pretty big, in which case i'm also thinking of having a minimum padding size and just make them scrollable.
bottom: TabBar(
labelPadding: EdgeInsets.only(left: 8, right: 8),
isScrollable: true,
tabs: <Widget>[
Tab(
text: 'General',
),
Tab(
text: 'Financial',
),
Tab(
text: 'Experts & Participants',
),
],
)),
The way the TabBar
is implemented, doesn't allow to set flexible tabs. So you have to calculate the horizontal padding for each tab.
You'll need to get the tab widths, so you could do this:
GlobalKey
to each Tab
and then access to
key.currentContext.size.width
.key.currentContext
would be null
during build, you need to
wait until the TabBar
is rendered and then get the tabs width. To do
that, you could use WidgetsBinding.instance.addPostFrameCallback()
inside initState
.didChangeDependencies
instead of
initState
.setState
to update the padding of the tabs.setState
in the entire tree, you could put the
TabBar
in a custom StatefulWidget
.TabBar
in the app, you could create a
custom TabBar
widget, that receives the TabBar
and return a new one
with the calculated padding.So, depending on your case, you could implement some or all of the points mentioned. Here is an example with all the points mentioned:
class TabBarWithFlexibleTabs extends StatefulWidget implements PreferredSizeWidget {
TabBarWithFlexibleTabs({this.child});
final TabBar child;
@override
Size get preferredSize => child.preferredSize;
@override
_TabBarWithFlexibleTabsState createState() => _TabBarWithFlexibleTabsState();
}
class _TabBarWithFlexibleTabsState extends State<TabBarWithFlexibleTabs> {
final _tabs = <Widget>[];
final _tabsKeys = <Tab, GlobalKey>{};
var _tabsPadding = 0.0;
void _updateTabBarPadding() => setState(() {
final screenWidth = MediaQuery.of(context).size.width;
final tabBarWidth = _tabsKeys.values
.fold(0, (prev, tab) => prev + tab.currentContext.size.width);
_tabsPadding = tabBarWidth < screenWidth
? ((screenWidth - tabBarWidth) / widget.child.tabs.length) / 2
: widget.child.labelPadding?.horizontal ?? 16.0;
});
@override
void initState() {
super.initState();
widget.child.tabs.forEach((tab) => _tabsKeys[tab] = GlobalKey());
_tabs.addAll(widget.child.tabs
.map((tab) => Container(key: _tabsKeys[tab], child: tab)));
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
WidgetsBinding.instance.addPostFrameCallback((_) => _updateTabBarPadding());
}
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: widget.child.tabs.length,
child: TabBar(
tabs: _tabs,
isScrollable: true,
labelPadding: EdgeInsets.symmetric(
horizontal: _tabsPadding,
vertical: widget.child.labelPadding?.vertical ?? 0,
),
// TODO: pass other parameters used in the TabBar received, like this:
controller: widget.child.controller,
indicatorColor: widget.child.indicatorColor,
),
);
}
}
And you could use it like this:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
bottom: TabBarWithFlexibleTabs(
child: TabBar(
tabs: <Widget>[
Tab(
text: 'General',
),
Tab(
text: 'Financial',
),
Tab(
text: 'Experts & Participants',
),
],
),
)
),
);
}
Notes:
TabBar
will be scrollable if it can't fit the screen width.// TODO: pass other parameters used in the TabBar received
.DefaultTabController
if you want to use
a custom one.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With