Favor
Favor

Reputation: 870

Hide Appbar on Scroll Flutter?

Sample Image

Consider this image. As you can see it has an appbar and the appbar has Tabbed buttons. Am trying to animate the appbar so that it hides on scrollup and leaves only the Tab Buttons showing and on scrollup the appbar apears. Please help me out. Sorry for bad english and not American neither am I English

Upvotes: 40

Views: 95558

Answers (6)

CopsOnRoad
CopsOnRoad

Reputation: 268404

Screenshot:

enter image description here


Code:

As I mentioned here, you can use NestedScrollView like this:

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: DefaultTabController(
      length: 2,
      child: NestedScrollView(
        headerSliverBuilder: (context, value) {
          return [
            SliverAppBar(
              title: Text('AppBar'),
              pinned: true,
              floating: true,
              bottom: TabBar(
                tabs: [
                  Tab(icon: Icon(Icons.call), text: 'Call'),
                  Tab(icon: Icon(Icons.message), text: 'Message'),
                ],
              ),
            ),
          ];
        },
        body: TabBarView(
          children: [
            FlutterLogo(),
            FlutterLogo(),
          ],
        ),
      ),
    ),
  );
}

Upvotes: 2

Marcin Szałek
Marcin Szałek

Reputation: 5069

If I understood you correctly, following code should make the app bar hide on scroll while TabBar remains visible:

Null safe code:

class _SomePageState extends State<SomePage> with SingleTickerProviderStateMixin {
  late final TabController _tabController;

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: NestedScrollView(
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            SliverAppBar(
              title: Text('Weight Tracker'),
              pinned: true,
              floating: true,
              forceElevated: innerBoxIsScrolled,
              bottom: TabBar(
                tabs: <Tab>[
                  Tab(text: 'STATISTICS'),
                  Tab(text: 'HISTORY'),
                ],
                controller: _tabController,
              ),
            ),
          ];
        },
        body: TabBarView(
          controller: _tabController,
          children: <Widget>[
            StatisticsPage(),
            HistoryPage(),
          ],
        ),
      ),
    );
  }
}

enter image description here

Example coming from this post.

Upvotes: 100

Kapil Sahu
Kapil Sahu

Reputation: 599

I was able to make the floating appbar with tabbar similar to that of WhatsApp by using SliverAppbar with NestedScrollView.

Do add floatHeaderSlivers: true, in NestedScrollView and

pinned: true, floating: true, in SliverAppBar

Link to sample 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

Upvotes: 5

Jitesh Mohite
Jitesh Mohite

Reputation: 34270

Using DefaultTabController

DefaultTabController(
      length: 2,
      child: new Scaffold(
        body: new NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return <Widget>[
              new SliverAppBar(
                title: Text("Application"),
                floating: true,
                pinned: true,
                snap: true,
                bottom: new TabBar(
                  tabs: <Tab>[
                    new Tab(text: "T"),
                    new Tab(text: "B"),
                  ], // <-- total of 2 tabs
                ),
              ),
            ];
          },
          body: new TabBarView(
            children: <Widget>[
              Center(
                  child: Text(
                'T Tab',
                style: TextStyle(fontSize: 30),
              )),
              Center(
                  child: Text(
                'B Tab',
                style: TextStyle(fontSize: 30),
              )),
            ],
          ),
        ),
      ),
    );

Output:

enter image description here

Upvotes: 9

Snehal Masalkar
Snehal Masalkar

Reputation: 79

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

void main() => runApp(MyApp());

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

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  bool _showAppbar = true;
  ScrollController _scrollBottomBarController = new ScrollController();
  bool isScrollingDown = false;
  bool _show = true;
  double bottomBarHeight = 75;
  double _bottomBarOffset = 0;

  @override
  void initState() {
    super.initState();
    myScroll();    
  }

  @override
  void dispose() {
    super.dispose();
    _scrollBottomBarController.removeListener(() {});
    super.dispose();
  }

  void showBottomBar() {
    setState(() {
      _show = true;
    });
  }

  void hideBottomBar() {
    setState(() {
      _show = false;
    });
  }

  void myScroll() async {
    _scrollBottomBarController.addListener(() {
      if (_scrollBottomBarController.position.userScrollDirection ==
          ScrollDirection.reverse) {
        if (!isScrollingDown) {
          isScrollingDown = true;
          _showAppbar = false;
          hideBottomBar();
        }
      }
      if (_scrollBottomBarController.position.userScrollDirection ==
          ScrollDirection.forward) {
        if (isScrollingDown) {
          isScrollingDown = false;
          _showAppbar = true;
          showBottomBar();
        }
      }
    });
  }

  Widget containterContent(){
    return Container(
      height: 50.0,
      color: Colors.cyanAccent,
      margin: EdgeInsets.all(8.0),
      width: MediaQuery.of(context).size.width - 100,
      child: Center(child: Text('Item 1',
        style: TextStyle(
          fontSize: 14.0,
        ),)),
    );
  }

  Widget body() {
    return ListView(
      controller: _scrollBottomBarController,
      children: <Widget>[
        containterContent(),
        containterContent(),
        containterContent(),
        containterContent(),
        containterContent(),
        containterContent(),
        containterContent(),
        containterContent(),
        containterContent(),
        containterContent(),

      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: _showAppbar
          ? AppBar(
        title: Text('My Tasks'),
      )
          : PreferredSize(
        child: Container(),
        preferredSize: Size(0.0, 0.0),
      ),
      bottomNavigationBar: Container(
        height: bottomBarHeight,
        width: MediaQuery.of(context).size.width,
        child: _show
            ?BottomNavigationBar(
          currentIndex: 0, // this will be set when a new tab is tapped
          items: [
            BottomNavigationBarItem(
              icon: new Icon(Icons.home),
              title: new Text('Home'),
            ),
            BottomNavigationBarItem(
              icon: new Icon(Icons.mail),
              title: new Text('Messages'),
            ),
            BottomNavigationBarItem(
                icon: Icon(Icons.person), title: Text('Profile'))
          ],
        )
            : Container(
          color: Colors.white,
          width: MediaQuery.of(context).size.width,
        ),
      ),

      body: body(
      ),

    );
  }
}

Upvotes: 7

Viren V Varasadiya
Viren V Varasadiya

Reputation: 27197

I suggest that you have to go through SliverAppBar and SliverList To achieve your layout. Following code may help you to understand that.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      home: new MyHomePage(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {

    List buildTextViews(int count) {
      List<Widget> strings = List();
      for (int i = 0; i < count; i++) {
        strings.add(new Padding(padding: new EdgeInsets.all(16.0),
            child: new Text("Item number " + i.toString(),
                style: new TextStyle(fontSize: 20.0))));
      }
      return strings;
    }

    return Scaffold(
        body: new CustomScrollView(slivers: <Widget>[
          const SliverAppBar(
            title: const Text('Sliver App Bar'),
          ),
          new SliverList(
              delegate: new SliverChildListDelegate(buildTextViews(50)))
        ])
    );
  }
}

Upvotes: 8

Related Questions