Reputation: 870
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
Reputation: 268404
Screenshot:
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
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(),
],
),
),
);
}
}
Example coming from this post.
Upvotes: 100
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
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)],
);
},
),
);
}
}
Upvotes: 5
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:
Upvotes: 9
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
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