Flutter TabBar Example – WeightTracker 5

Flutter TabBar Example – WeightTracker 5

In this short post I will document how I added TabBar to my WeightTracker app.

Note: I am using Redux to populate data to view, if you are not familiar with Redux, just ignore StoreConnector widget and focus only on Builder body which can be treated like normal build function.

In order to add Tabs to application, all I needed was to create TabBar and TabBarView and attach TabController to them. TabController will sync TabBar with TabBarView so we can have behaviour we wanted.

class MainPageState extends State<MainPage> with SingleTickerProviderStateMixin{
  TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = new TabController(vsync: this, length: 2);

  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return new StoreConnector<ReduxState, MainPageViewModel>(
      converter: (store) {
        return new MainPageViewModel([...]);
      },
      builder: (context, viewModel) {
        return new Scaffold(
            appBar: new AppBar(
              title: new Text(widget.title),
              bottom: new TabBar(
                tabs: <Tab>[
                  new Tab(
                    text: "STATISTICS",
                    icon: new Icon(Icons.show_chart),
                  ),
                  new Tab(
                    text: "HISTORY",
                    icon: new Icon(Icons.history),
                  ),
                ],
                controller: _tabController,
              ),
            ),
            body: new TabBarView(
              children: <Widget>[
                new StatisticsPage(),
                new HistoryPage(),
              ],
              controller: _tabController,
            ),
            floatingActionButton: [...]
        );
      },
    );
  }
}

However, I didn’t want title widget to stick on the top of screen forever. To add nice hiding behaviour, I introduced NestedScrollView with SliverAppBar:

class MainPageState extends State<MainPage> with SingleTickerProviderStateMixin {
  ScrollController _scrollViewController;
  TabController _tabController;

  @override
  void initState() {
    super.initState();
    _scrollViewController = new ScrollController();
    _tabController = new TabController(vsync: this, length: 2);
  }

  @override
  void dispose() {
    _scrollViewController.dispose();
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return new StoreConnector<ReduxState, MainPageViewModel>(
      converter: (store) {
        return new MainPageViewModel([...]);
      },
      builder: (context, viewModel) {
        return new Scaffold(
          body: new NestedScrollView(
            controller: _scrollViewController,
            headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
              return <Widget>[
                new SliverAppBar(
                  title: new Text(widget.title),
                  pinned: true,
                  floating: true,
                  forceElevated: innerBoxIsScrolled,
                  bottom: new TabBar(
                    tabs: <Tab>[
                      new Tab(
                        text: "STATISTICS",
                        icon: new Icon(Icons.show_chart),
                      ),
                      new Tab(
                        text: "HISTORY",
                        icon: new Icon(Icons.history),
                      ),
                    ],
                    controller: _tabController,
                  ),
                ),
              ];
            },
            body: new TabBarView(
              children: <Widget>[
                new StatisticsPage(),
                new HistoryPage(),
              ],
              controller: _tabController,
            ),
          ),
          floatingActionButton: [...]
        );
      },
    );
  }
}

And that’s it.

If you are interested in full code shown in this post, see my github repository. 🙂

Leave a Reply

Your email address will not be published.