4

Can we add TabBar in our SliverAppBar?

Since SliverAppBar has the bottom property, I thought we can add Tabbar in our SliverAppBar, but the problem is TabBar needs DefaultTabbarController and DefaultTabbarController only works in Material Widget and SliverAppbar only works in Scaffold Body, not in my appbar, but I need my scaffold body to have TabView. What is the explanation?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Theodorus Agum Gumilang
  • 1,414
  • 4
  • 23
  • 46
  • What you are trying to achieve is not clear. Please post the code. – ap14 Jul 11 '18 at 05:06
  • what i trying to do is i want make appbar that will hide when the users is scrolling, so i found on the internet if this can be achieve using SliverAppBar, but now i want add Tabbar to my SliverAppBar . So when users scrolling it will hide the SliverAppBar and left the TabbBar only just like in WhatsApp – Theodorus Agum Gumilang Jul 11 '18 at 05:40
  • Checkout this answer https://stackoverflow.com/questions/50433885/sliverappbar-with-tabbar/50853287#50853287 – marp Sep 30 '18 at 10:48

3 Answers3

9

Yes, you can add Tabbar inside SliverAppBar using NestedScrollView. You can also customise the appbar similar to that of whatsapp i.e floating appbar. Do make sure to add floatHeaderSlivers: true, in NestedScrollView for this. Link to working code

import 'dart:math';
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: CustomSliverAppbar(),
    );
  }
}

class CustomSliverAppbar extends StatefulWidget {
  @override
  _CustomSliverAppbarState createState() => _CustomSliverAppbarState();
}

class _CustomSliverAppbarState extends State<CustomSliverAppbar>
    with SingleTickerProviderStateMixin {
  TabController _tabController;

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: NestedScrollView(
        floatHeaderSlivers: true,
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            SliverAppBar(
              title: Text(
                "WhatsApp type sliver appbar",
              ),
              centerTitle: true,
              pinned: true,
              floating: true,
              bottom: TabBar(
                  indicatorColor: Colors.black,
                  labelPadding: const EdgeInsets.only(
                    bottom: 16,
                  ),
                  controller: _tabController,
                  tabs: [
                    Text("TAB A"),
                    Text("TAB B"),
                  ]),
            ),
          ];
        },
        body: TabBarView(
          controller: _tabController,
          children: [
            TabA(),
            const Center(
              child: Text('Display Tab 2',
                  style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
            ),
          ],
        ),
      ),
    );
  }

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

class TabA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scrollbar(
      child: ListView.separated(
        separatorBuilder: (context, child) => Divider(
          height: 1,
        ),
        padding: EdgeInsets.all(0.0),
        itemCount: 30,
        itemBuilder: (context, i) {
          return Container(
            height: 100,
            width: double.infinity,
            color: Colors.primaries[Random().nextInt(Colors.primaries.length)],
          );
        },
      ),
    );
  }
}

enter image description here

Kapil Sahu
  • 469
  • 7
  • 14
4

You can wrap SilverAppBar(which has TabBar as bottom) & SilverFillRemaining(wraps TabBarView) with CustomScrollView. Then set CustomScrollView as body of Scaffold. For this you need to create a TabController.

Full example here:

import 'package:flutter/material.dart';

class SilverAppBarWithTabBarScreen extends StatefulWidget {
  @override
  _SilverAppBarWithTabBarState createState() => _SilverAppBarWithTabBarState();
}

class _SilverAppBarWithTabBarState extends State<SilverAppBarWithTabBarScreen>
    with SingleTickerProviderStateMixin {
  TabController controller;

  @override
  void initState() {
    super.initState();
    controller = new TabController(length: 3, vsync: this);
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new CustomScrollView(
        slivers: <Widget>[
          new SliverAppBar(
            title: Text("Silver AppBar With ToolBar"),
            pinned: true,
            expandedHeight: 160.0,
            bottom: new TabBar(
              tabs: [
                new Tab(text: 'Tab 1'),
                new Tab(text: 'Tab 2'),
                new Tab(text: 'Tab 3'),
              ],
              controller: controller,
            ),
          ),
          new SliverFillRemaining(
            child: TabBarView(
              controller: controller,
              children: <Widget>[
                Text("Tab 1"),
                Text("Tab 2"),
                Text("Tab 3"),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dhiraj Sharma
  • 4,364
  • 24
  • 25
  • 1
    hi thanks for your answer , i have question . why when i'm scrolling in my TabbBarView my appbar don't hide itself, isn't SliverAppBar created to fullfill those purpose ? or maybe i shhould add something here ? – Theodorus Agum Gumilang Jul 11 '18 at 05:45
  • Edit now the problem is myapbar wont react to my listvew scrolling, but its work well when my tabview just text, and second can i hide my appbar only without the bottom(tabbar) , – Theodorus Agum Gumilang Jul 11 '18 at 06:28
1

I was able to achieve what you was asking. But I have only one problem, i.e., when I add a scrolling widget in TabView it doesn't produce the required result.

I have open an issue on GitHub.

Here is my code:

class HomePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => HomePageState();
}

class HomePageState extends State<HomePage>
    with SingleTickerProviderStateMixin {
  TabController tabController;
  @override
  void initState() {
    super.initState();
    tabController = TabController(length: 2, vsync: this);
  }

  @override
  Widget build(BuildContext context) {
    Color tabColor = Theme.of(context).primaryColorDark;
    TextStyle tabStyle = TextStyle(color: tabColor);
    return SafeArea(
      child: Scaffold(
        body: CustomScrollView(
          slivers: <Widget>[
            SliverAppBar(
              title: Text("AppBar"),
              floating: true,
              primary: true,
              pinned: false,
            ),
            SliverFillRemaining(
              child: Scaffold(
                appBar: TabBar(
                controller: tabController,
                tabs: <Widget>[
                  Tab(
                    child: Text(
                      'Tab1',
                     style: tabStyle,
                    ),
                  ),
                  Tab(
                    child: Text(
                      'Tab2',
                    style: tabStyle,
                    ),
                  ),
                ],
              ),
                body: TabBarView(
                  controller: tabController,
                  children: <Widget>[
                    Scaffold(
                      body: Text('Tab One'),
                    ),
                    Scaffold(
                      body: Text('Tab Two'),
                    ),
                  ],
                ),
              ),
              ),
          ],
        ),
      ),
    );
  }
}

Emulator Screen

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ap14
  • 4,393
  • 1
  • 15
  • 30