'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

Flutter tabs screen



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 ^^

TabBar with border

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(
        ...
    ),
),

enter image description here

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