Reputation: 557
I'm having trouble with app bar animation, I'm using SilverAppBar
, in my app. So, the problem is when I'm in the middle of my list and I scroll up, the app bar does not appear, but it appears just when scrolling reaches the top of the items list. I already tested the snap
parameter and give it true
, but not the result I expect. I have ideas about creating a custom animation for this, but I'm not too experienced in Flutter, and also if there is a way to add parameters, or another widget that will work for my situation, it would be great.
The actual code of the demo I'm using:
Widget _search() => Container(
color: Colors.grey[400],
child: SafeArea(
child: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
enabled: false,
style: TextStyle(fontSize: 16, color: Colors.white),
decoration: InputDecoration(
prefix: SizedBox(width: 12),
hintText: "Search",
contentPadding:
EdgeInsets.symmetric(horizontal: 32.0, vertical: 14.0),
border: InputBorder.none,
),
),
),
)),
);
Container _buildBody() {
return Container(
child: new GridView.count(
crossAxisCount: 2,
children: List.generate(100, (index) {
return Center(
child: Text(
'Item $index',
style: Theme.of(context).textTheme.headline,
),
);
}),
));
}
@override
Widget build(BuildContext context) {
return new Scaffold(
resizeToAvoidBottomPadding: false,
body: new NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
new SliverAppBar(
title: Text("Demo",
style: TextStyle(
color: Colors.white,
)),
pinned: false,
floating: true,
forceElevated: innerBoxIsScrolled,
),
];
},
body: new Column(children: <Widget>[
_search(),
new Expanded(child: _buildBody())
])));
}
The result I have now: Image 1
The result I got after giving true
to the snap
parameter:
Image 2
Plenty of applications like WhatsApp, Facebook, LinkedIn ... have this animating app bar. To explain more what exactly I expect with this animating app bar, I added an example of Google Play Store, showing the wanted animation: Play Store example
Upvotes: 2
Views: 17579
Reputation: 599
I was able to make the floating Appbar with Tabbar similar to that of WhatsApp by using SliverAppbar with NestedScrollView. Do remember to add floatHeaderSlivers: true, in NestedScrollView. 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)],
);
},
),
);
}
}
Upvotes: 5
Reputation: 596
I had a similar issue with CustomScrollView and SliverAppbar using refresh indicator i ended up creating my own custom appbar.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class HomeView extends StatefulWidget {
@override
HomeState createState() => HomeState();
}
class HomeState extends State<HomeView> with SingleTickerProviderStateMixin {
bool _isAppbar = true;
ScrollController _scrollController = new ScrollController();
@override
void initState() {
super.initState();
_scrollController.addListener(() {
if (_scrollController.position.userScrollDirection ==
ScrollDirection.reverse) {
appBarStatus(false);
}
if (_scrollController.position.userScrollDirection ==
ScrollDirection.forward) {
appBarStatus(true);
}
});
}
void appBarStatus(bool status) {
setState(() {
_isAppbar = status;
});
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(kToolbarHeight),
child: AnimatedContainer(
height: _isAppbar ? 55.0 : 0.0,
duration: Duration(milliseconds: 200),
child: CustomAppBar(),
),
),
body: ListView.builder(
controller: _scrollController,
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return container();
},
),
),
);
}
}
Widget container() {
return Container(
height: 80.0,
color: Colors.pink,
margin: EdgeInsets.all(8.0),
width: 100,
child: Center(
child: Text(
'Container',
style: TextStyle(
fontSize: 18.0,
),
)),
);
}
class CustomAppBar extends StatefulWidget {
@override
AppBarView createState() => new AppBarView();
}
class AppBarView extends State<CustomAppBar> {
@override
Widget build(BuildContext context) {
return AppBar(
backgroundColor: Colors.white,
leading: InkWell(
onTap: () => {},
child: new Padding(
padding: const EdgeInsets.all(8.0),
child: CircleAvatar(
backgroundColor: Colors.white,
child: ClipOval(
child: Image.network(
'https://images.squarespace-cdn.com/content/5aee389b3c3a531e6245ae76/1530965251082-9L40PL9QH6PATNQ93LUK/linkedinPortraits_DwayneBrown08.jpg?format=1000w&content-type=image%2Fjpeg'),
),
),
),
),
actions: <Widget>[
IconButton(
alignment: Alignment.centerLeft,
icon: Icon(
Icons.search,
color: Colors.black,
),
onPressed: () {},
),
],
title: Container(
alignment: Alignment.centerLeft,
child: Text("Custom Appbar", style: TextStyle(color: Colors.black),)
),
);
}
}
Upvotes: 6
Reputation: 1963
To get this functionality to work, you will need to use the CustomScrollView
widget instead of NestedScrollView
. Google Documentation
Here is a working example:
class MyHomeState extends State<MyHome> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
const SliverAppBar(
pinned: false,
snap: false,
floating: true,
flexibleSpace: FlexibleSpaceBar(
title: Text('Demo'),
),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 4.0,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.teal[100 * (index % 9)],
child: Text('grid item $index'),
);
},
childCount: 50,
),
),
],
)
);
}
}
Upvotes: 4