pl8nt
pl8nt

Reputation: 49

Make tab bar's selected tab underline be only as long as the label text

I want to be able to have the selected tab's underline within the tab bar to only be as long as the text for that tab (as shown below). I believe my issue is that I have a SizedBox with a defined width that uses the screen's width to determine the width of each tab. I did this since there would be a scroll with the "SHARE THE GOOD" tab as it's too long and I want all the tabs to fit on the screen with no scroll.

Here's the code I have for creating that tab bar

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  static TextStyle tabTextStyle = smallCaps13;

  @override
  Widget build(BuildContext context) {
    final double width = MediaQuery.of(context).size.width;
    final List<Widget> tabs = [
      SizedBox(
        width: width * 0.25,
        // padding: const EdgeInsets.symmetric(horizontal: 80.0),
        child: const Tab(child: Text("HOME")),
      ),
      SizedBox(
        width: width * 0.25,
        // padding: const EdgeInsets.symmetric(horizontal: 80.0),
        child: const Tab(child: Text("NEWS")),
      ),
      SizedBox(
        width: width * 0.5,
        // padding: const EdgeInsets.symmetric(horizontal: 80.0),
        child: const Tab(child: Text("SHARE THE GOOD")),
      ),
    ];
    return DefaultTabController(
      length: tabs.length,
      child: Column(
        children: [
          TabBar(
            indicatorSize: TabBarIndicatorSize.label,
            dividerColor: Colors.transparent,
            splashFactory: NoSplash.splashFactory,
            labelStyle: smallCaps13.copyWith(color: ftiDarkBlue),
            unselectedLabelColor: ftiMediumGray,
            tabAlignment: TabAlignment.start,
            indicatorColor: Theme.of(context).colorScheme.secondary,
            labelPadding: const EdgeInsets.symmetric(horizontal: 0),
            isScrollable: true,
            tabs: tabs,
          ),
          const Expanded(
            child: TabBarView(
              children: [
                HomeTab(),
                NewsTab(),
                ShareTheGoodTab(),
              ],
            ),
          )
        ],
      ),
    );
  }
}

I tried adding indicatorSize: TabBarIndicatorSize.label, to no avail as it's still considering that whole SizedBox which makes sense.

Upvotes: 0

Views: 135

Answers (1)

Md. Yeasin Sheikh
Md. Yeasin Sheikh

Reputation: 63769

You can have the default controller access like DefaultTabController.maybeOf(context) but you need to go one level down to the context tree. I would say use a TabController.

The constraints left on your custom width of the TabBar item which isn't equal to the text. You can build it with Row, you can use Row/Column.

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  static TextStyle tabTextStyle = const TextStyle();

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen>
    with SingleTickerProviderStateMixin {
  late final tabController = TabController(length: 3, vsync: this);
  @override
  void dispose() {
    tabController.dispose();
    super.dispose();
  }

  final tabTitles = ["HomeTab", "News", "Share the good"];
  @override
  Widget build(BuildContext context) {
    ///
    Widget _buildTab(int index, String text) {
      return Expanded(
        child: InkWell(
          onTap: () {
            tabController.animateTo(index);
            setState(() {});
          },
          child: Tab(
            child: DecoratedBox(
              decoration: index == tabController.index
                  ? const BoxDecoration(
                      border: Border(
                        bottom: BorderSide(
                          color: Colors.black,
                          width: 2.0,
                        ),
                      ),
                    )
                  : const BoxDecoration(),
              child: Text(text, style: HomeScreen.tabTextStyle),
            ),
          ),
        ),
      );
    }

    return Column(
      children: [
        Row(
          children: [for (int i = 0; i < 3; i++) _buildTab(i, tabTitles[i])],
        ),
        Expanded(
          child: TabBarView(
            controller: tabController,
            children: [
              Text("HOME"),
              Text("NEWS"),
              Text("SHARE THE GOOD"),
              // HomeTab(),
              // NewsTab(),
              // ShareTheGoodTab(),
            ],
          ),
        )
      ],
    );
  }
}

Upvotes: 1

Related Questions