Add bottom border of to tabs in Flutter
Asked Answered
T

10

9

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

Tailwind answered 2/8, 2019 at 20:39 Comment(0)
C
7

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),
            ],
          ),
        ),
      ),
    );
  }
}
Communicant answered 2/8, 2019 at 21:28 Comment(2)
Nice work! So simple, more than my own solution, so I considered it. Thanks a lot.Tailwind
If i have 5 tabs, and each have same width as above so how can i show it so that i can scroll them horizontally?Hoplite
M
7

Try to set appBar border :

appBar: AppBar(
    shape: Border(bottom: BorderSide(color: Colors.red)),
     .... 
Melodymeloid answered 2/8, 2019 at 22:0 Comment(2)
what you suggested is too close, it's only under the indicatorColor. I did it using the solution I just posted. Thanks a lot for your help.Tailwind
there is no appBar within TabBarWarrantor
D
7

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.

Decrepitate answered 1/11, 2021 at 11:42 Comment(1)
It sets bottom side border color for all inactive tabs, not for active one. Not sure how you get that output in the screenshot.Imprint
T
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

Tailwind answered 2/8, 2019 at 22:15 Comment(0)
A
3

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),
                        ),
                      ],
                    ),
                  ],
                ),
Apostles answered 2/12, 2020 at 10:20 Comment(0)
T
1

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,
  ),
),
Tailwind answered 2/8, 2019 at 23:16 Comment(1)
Thanks for the labelPadding hint!Kiangsu
T
1

I would like to add an answer

all answers have a problem due to which the bottom line is either higher or lower than the indicator, and it is also quite difficult to control its height.

Well. here is a working version in flutter 3

                  PreferredSize(
                    preferredSize: Size.fromHeight(kToolbarHeight),
                    child: DecoratedBox(
                      decoration: BoxDecoration(
                        border: Border(
                          bottom: BorderSide(
                            color: AppColors.border,
                            width: 3,
                          ),
                        ),
                      ),
                      child: TabBar(
                        labelColor: AppColors.secondText,
                        unselectedLabelColor: AppColors.grayText,
                        indicator: UnderlineTabIndicator(
                          borderSide: BorderSide(
                              width: 3.0, color: AppColors.secondText),
                          insets: EdgeInsets.symmetric(horizontal: 30.0),
                        ),
                        tabs: [
                          Tab(
                            text: "Tab 1",
                          ),
                          Tab(
                            text: "Tab 2",
                          ),
                        ],
                      ),
                    ),
                  ),
    
Tyler answered 9/6, 2023 at 13:17 Comment(0)
F
1

You can use TabBar dividerColor property.

Fugato answered 27/11, 2023 at 21:14 Comment(0)
Y
0

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',
              ),
            ],
          ),
        ),
      ),
    ),
Yahweh answered 17/3, 2022 at 20:1 Comment(0)
I
0

Easiest way without using additional elements, is to use BoxShadow with TabBar like below:

TabBar(
                        controller: _tabController,
                        indicator: BoxDecoration(
                                                 boxShadow: [
                            BoxShadow(
                              color: Colors.red,                         
                              offset: Offset(0, 2.0),
                            )
                          ],
                        
                          color: Colors.white,
                        ),
                        labelColor: Colors.red,
                        unselectedLabelColor: Colors.grey.shade900,
                        labelPadding: EdgeInsets.symmetric(horizontal: 10.0),
                        isScrollable: false,
                        tabs: [
                          Tab(
                            text: 'T1',
                          ),
                          Tab(
                            text: 'T2',
                          ),
                          Tab(
                            text: 'T3',
                          ),
                          Tab(
                            text: 'T4',
                          ),
                        ],
                      ),

Or using UnderlineTabIndicator as indicator parameter of TabBar:

indicator: UnderlineTabIndicator(
                  borderSide: BorderSide(width: 3.0),
                  insets: EdgeInsets.symmetric(horizontal: 30.0),
                ),
Imprint answered 11/10, 2022 at 23:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.