'Add bottom border of to tabs in Flutter
What I'm trying to do is adding a bottom border of tabBar, so it will be under tabs title and above the indicatorColor and for both active and Inactive tabs, just like the attached image.
Red line is what I am trying to add, green line is the indicatorColor.
Note, usually I do this for appBar using 'bottom' but here bottom is reserved to the TabBar.
Is this possible?
Thanks a lot
Solution 1:[1]
You can set the AppBar shape property as abdulrahmanAbdullah says. But if you strictly need the border above the indicator, you can put it inside of each tab bar item. Here's one take on it:
import 'package:flutter/material.dart';
void main() {
runApp(TabBarDemo());
}
class TabBarDemo extends StatelessWidget {
Widget _createTab(String text) {
return Tab(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Container(
child: Center(child: Text(text)),
decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.black)))
)
),
]
),
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Colors.white,
),
home: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
elevation: 0,
bottom: TabBar(
labelPadding: EdgeInsets.all(0),
tabs: [
_createTab("Tab 1"),
_createTab("Tab 2"),
_createTab("Tab 3"),
],
),
title: Text('Tabs Demo'),
),
body: TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
),
);
}
}
Solution 2:[2]
Try to set appBar border :
appBar: AppBar(
shape: Border(bottom: BorderSide(color: Colors.red)),
....
Solution 3:[3]
I managed to do that using 'flexibleSpace' property instead 'bottom' property, as flexibleSpace can have any widget not only 'PreferredSizeWidget' like bottom.
So I gave a Column to the flexibleSpace, then I was able to put TabBar and the container inside that column, then using Matrix4.translationValues(0.0, -2.6, 0.0) I gave the container, which contain the border, a nigative-padding(or similar) so it moved to the top of the indicatorColor.
return SafeArea(
top: true,
child: Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(100.0),
child: AppBar(
backgroundColor: Theme.of(context).buttonColor,
title: Text(
'AppBar',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.title,
),
centerTitle: true,
elevation: 0.0,
flexibleSpace: Padding(
padding: const EdgeInsets.only(top: 50.0),
child: Column(
children: <Widget>[
// Tab Bar
new TabBar(
indicatorColor: Theme.of(context).accentColor,
tabs: <Tab>[
new Tab(
text: 'Tab1',
),
new Tab(
text: 'Tab2',
),
],
controller: _tabController,
),
// Border
Container(
// Negative padding
transform: Matrix4.translationValues(0.0, -2.6, 0.0),
// Add top border
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: Color(0xFFc3c3c3),
width: 0.6,
),
),
),
),
],
),
),
),
),
body: new TabBarView(
children: <Widget>[
new Tab1(),
new Tab2(),
],
controller: _tabController,
),
),
);
And the magic happened ^^
Solution 4:[4]
Simply you can wrap TabBar into DecoratedBox as below:
DecoratedBox(
decoration: BoxDecoration(
//This is for background color
color: Colors.white.withOpacity(0.0),
//This is for bottom border that is needed
border: Border(
bottom: BorderSide(color: AppColors.color4, width: 2.sp)),
),
child: TabBar(
...
),
),
Hope you will get help.
Solution 5:[5]
Here's my version of spenster's solution;
Instead of a function, I created a new widget "BorderedTab" which implements Tab:
import 'package:flutter/material.dart';
class BorderedTab extends StatelessWidget implements Tab {
const BorderedTab({
Key key,
this.text,
this.borderColor=Colors.grey,
this.width=0.5,
}) : super(key: key);
final String text;
final Color borderColor;
final double width;
@override
Widget build(BuildContext context) {
return Tab(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Container(
child: Center(
child: Text(text)
),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
width: width,
color: borderColor,
),
),
),
),
),
]
),
);
}
@override
// TODO: implement child
Widget get child => null;
@override
// TODO: implement icon
Widget get icon => null;
}
then I used BorderedTab just like the regular Tab, but with:
labelPadding: EdgeInsets.all(0.0), // Important to remove default padding
Final AppBar:
import 'package:../widgets/bordered_tab.dart';
...
appBar: AppBar(
backgroundColor: Theme.of(context).buttonColor,
title: Text(
'TabBar',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.title,
),
centerTitle: true,
elevation: 0.0,
bottom: new TabBar(
labelColor: Theme.of(context).primaryColor,
indicatorColor:Theme.of(context).accentColor,
labelPadding: EdgeInsets.all(0.0), // Important to remove default padding
tabs: <Tab>[
BorderedTab(
text: 'Tab1',
borderColor: Color(0xFFc3c3c3),
),
BorderedTab(
text: 'Tab2',
borderColor: Color(0xFFc3c3),
),
],
controller: _tabController,
),
),
Solution 6:[6]
Another approach is to use a stack and place the line underneath the tabs
Stack(
alignment: Alignment.bottomCenter,
children: [
Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.white70, width: 1),
)),
),
TabBar(
indicatorWeight: 3.0,
tabs: [
Tab(
icon: Icon(Icons.home),
),
Tab(
icon: Icon(Icons.show_chart),
),
],
),
],
),
Solution 7:[7]
Use DecoratedBox and PreferredSize
First put TabBar inside of PreferredSize :
child: AppBar(
bottom: PreferredSize(
preferredSize: Size.fromHeight(50),
child: TabBar(
tabs: [
Tab(
text: 'tab-1',
),
Tab(
text: 'tab-2',
),
Tab(
text: 'tab-3',
),
],
),
),
),
then wrap TabBar with DecoratedBox
child: AppBar(
bottom: PreferredSize(
preferredSize: Size.fromHeight(50),
child: DecoratedBox(
decoration: BoxDecoration(
border: Border(bottom: BorderSide(width: 2,color: Color.fromARGB(255, 255, 0, 0)))
),
child: TabBar(
tabs: [
Tab(
text: 'tab-1',
),
Tab(
text: 'tab-2',
),
Tab(
text: 'tab-3',
),
],
),
),
),
),
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | abdulrahmanAbdullah |
| Solution 3 | Jehad Nasser |
| Solution 4 | Pratik Butani |
| Solution 5 | Jehad Nasser |
| Solution 6 | 34m0 |
| Solution 7 | Sobhan Shahamat Nia |



