SliverAppBar
A material design app bar that integrates with a [CustomScrollView].
AppBar and SliverAppBar are The AppBar in Material Design, which is the Toolbar in Android
SliverAppBar is a Material Design-style title bar used in conjunction with CustomScrollView.
Unlike the AppBar, it can be expanded or shrunk.
Construction method:
const SliverAppBar({
Key key,
this.leading, // Left header
this.automaticallyImplyLeading = true.// If leading is null, whether to automatically populate a leading
this.title, / / title
this.actions, / / the menu
this.flexibleSpace, // Can expand the area, usually a FlexibleSpaceBar
this.bottom, // Bottom content area
this.elevation,
this.forceElevated = false.// Use with elevation, whether to display shadows when elevation is not 0
this.backgroundColor,
this.brightness,
this.iconTheme,
this.actionsIconTheme,
this.textTheme,
this.primary = true.this.centerTitle,
this.excludeHeaderSemantics = false.this.titleSpacing = NavigationToolbar.kMiddleSpacing,
this.expandedHeight, // The height after expansion
this.floating = false.// Whether to display the appBar immediately when swiping down
this.pinned = false.// Whether the appBar is set to the top
this.snap = false.// When the finger is released, whether the SliverAppBar expands/collapses depending on the current position
this.stretch = false.this.stretchTriggerOffset = 100.0.this.onStretchTrigger,
this.shape,
})
Copy the code
If you look at the AppBar constructor, you’ll notice that the AppBar constructor is all in here. Its attributes are also consistent. Let’s explain the public attributes in detail below:
-
Snap: Note that snap is used in combination with floading and requires floating=true, otherwise an error will be reported.
-
AutomaticallyImplyLeading: if it is true (the default), then the page can be rolled back, will add a back button.
-
Leading: a control displayed in front of the title, usually displaying the application logo on the home page; On other interfaces it is usually displayed as a back button
-
Title: The main content of the Toolbar, usually displayed as the title text for the current interface
-
Actions: a list of widgets that represent the menus displayed in the Toolbar. For common menus, iconbuttons are used. For infrequent menus, PopupMenuButton is usually used to display three dots that pop up a secondary menu
-
Bottom: An AppBarBottomWidget object, usually a TabBar. Use to display a Tab navigation bar below the Toolbar title
-
Elevation: The z-coordinate order of a control in an ink-and-paper design. The default value is 4. For a scrollable SliverAppBar, the value is 0 when the SliverAppBar is the same as the content, and for the Toolbar when the content is scrollable, FlexibleSpace: A control that is displayed below the AppBar with the same height as the AppBar, enabling special effects. This property is usually used in the SliverAppBar
-
BackgroundColor: The color of the APP bar. The default is themeData.primaryColor. Change values are usually used in conjunction with the following three properties
-
Brightness: the brightness of the App bar, there are two themes, white and black. The default value for ThemeData primaryColorBrightness
-
IconTheme: The color, transparency, and size information of the icon above the App bar. The default value is ThemeData primaryIconTheme
-
TextTheme: The text style on the App bar. The default value is ThemeData primaryTextTheme
-
CenterTitle: Indicates whether the title is displayed in the center. The default value varies depending on the OPERATING system
A simple SliverAppBar
SliverAppBar(
automaticallyImplyLeading: false,
elevation: 5,
forceElevated: true,
expandedHeight: 200,
floating: true,
snap: false,
pinned: true,
stretch: true,
flexibleSpace: FlexibleSpaceBar(
title: Text('SliverAppBar'),
background: Image.asset(
'images/pic1.jpg',
fit: BoxFit.fill,
),
// Whether the title is centered
centerTitle: false.// Header spacing
//titlePadding: EdgeInsetsDirectional.only(start: 0, bottom: 16),
collapseMode: CollapseMode.parallax,
))
Copy the code
Although it’s basically the same, the constructor is very simple, but we can’t use it directly, you can see from the official documentation that we usually use it in conjunction with a ScrollView.
Let’s look at an example with a CustomScrollView:
/ * * Created by Eunice li original on 2018/9/13. * email: [email protected] * * / import 'package: flutter/material. The dart'; class DiscoverListPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: NestedScrollView( headerSliverBuilder: _sliverBuilder, body: Center( child: ListView.builder( itemBuilder: _itemBuilder, itemCount: 15, ), )), ); } List<Widget> _sliverBuilder(BuildContext context, Bool innerBoxIsScrolled) {return <Widget>[SliverAppBar(centerTitle: true, // Title center) expandedHeight: 200.0, // Expand height 200 floating: false, // hides title pinned to the top without sliding: true, // Fixed on top flexibleSpace: FlexibleSpaceBar(centerTitle: True, title: Text(' I am a FlexibleSpaceBar'), background: Image.network( "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531798262708&di=53d278a8427f482c5b836fa0e057f4ea&i mgtype=0&src=http%3A%2F%2Fh.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F342ac65c103853434cc02dda9f13b07eca80883a.jpg", fit: BoxFit.cover, ), ), ) ]; } Widget _itemBuilder(BuildContext context, int index) { return ListTile( leading: Icon(Icons.android), title: Text(' peerless title +$index'),); }}Copy the code
First we added the SliverAppBar using the headerSliverBuilder property in the NestedScrollView
Then we set the height of the expansion to 200, so that the title bar doesn’t scroll out of the viewable area, and finally we add a 15-length ListView to the body of the NestedScrollView
Then let’s look at the effect:
We set the pinned attribute to false(not pinned to the top) and see what happens
Now let’s take a look at the bottom property, which allows us to place any widgets you want under it, so let’s put a TabBar and see
The code is simple, but we need to make DiscoverListPage inherit from StatefulWidget, then State with TickerProviderStateMixin, and add a bottom to the SliverAppBar. Modified code:
/ * * Created by Eunice li original on 2018/9/13. * email: [email protected] * * / import 'package: flutter/material. The dart'; class DiscoverListPage extends StatefulWidget { @override State<StatefulWidget> createState() => DiscoverListState(); } class DiscoverListState extends State<DiscoverListPage> with TickerProviderStateMixin { @override Widget build(BuildContext context) { return Scaffold( body: NestedScrollView( headerSliverBuilder: _sliverBuilder, body: Center( child: ListView.builder( itemBuilder: _itemBuilder, itemCount: 15, ), )), ); } List<Widget> _sliverBuilder(BuildContext context, Bool innerBoxIsScrolled) {return <Widget>[SliverAppBar(// centerTitle: true, // Expand height 200 expandedHeight: 200.0, // Does not hide title floating: false, // Fixed on top PINNED: false, flexibleSpace: FlexibleSpaceBar(centerTitle: true, title: Text(' I am a FlexibleSpaceBar'), background: Image.network( "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531798262708&di=53d278a8427f482c5b836fa0e057f4ea&i mgtype=0&src=http%3A%2F%2Fh.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F342ac65c103853434cc02dda9f13b07eca80883a.jpg", // bottom this is new this is new this is new this is new this is new bottom: TabBar(tabs: [Tab(icon: icon (icon.cake)), text: "), Tab(icon: icon (Icons. Golf_course), text: "),], Controller: TabController(length: 2, vsync: this),),)]; } Widget _itemBuilder(BuildContext context, int index) { return ListTile( leading: Icon(Icons.android), title: Text(' peerless title +$index'),); }}Copy the code
Look at the effect:It’s — it’s too ugly to look at. Of course we want the TabBar to be underneath the SliverAppBar and scroll with it.
Because of the height of the TabBar, we can’t slide the SliverAppBar to the top, so it’s not appropriate to put the TabBar in the bottom to move as the SliverAppBar moves. In this case, we can rely on the SliverPersistentHeader property in the SliverPersistentHeader
The construction of a SliverPersistentHeader is simple, with just a few simple properties, so I won’t go into specifics
const SliverPersistentHeader({
Key key,
@required this.delegate,
this.pinned = false,
this.floating = false,
})
Copy the code
The complete code is as follows:
/ * * Created by Eunice li original on 2018/9/13. * email: [email protected] * * / import 'package: flutter/material. The dart'; class DiscoverListPage extends StatefulWidget { @override State<StatefulWidget> createState() => DiscoverListState(); } class DiscoverListState extends State<DiscoverListPage> with TickerProviderStateMixin { @override Widget build(BuildContext context) { return Scaffold( body: NestedScrollView( headerSliverBuilder: _sliverBuilder, body: Center( child: ListView.builder( itemBuilder: _itemBuilder, itemCount: 15, ), )), ); } List<Widget> _sliverBuilder(BuildContext context, Bool innerBoxIsScrolled) {return <Widget>[SliverAppBar(// centerTitle: true, // Expand height 200 expandedHeight: 200.0, // Does not hide title floating: false, // Fixed on top PINNED: false, flexibleSpace: FlexibleSpaceBar(centerTitle: true, title: Text(' I am a FlexibleSpaceBar'), background: Image.network( "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531798262708&di=53d278a8427f482c5b836fa0e057f4ea&i mgtype=0&src=http%3A%2F%2Fh.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F342ac65c103853434cc02dda9f13b07eca80883a.jpg", fit: BoxFit.cover, ), ), ), SliverPersistentHeader( delegate: _SliverAppBarDelegate(TabBar( labelColor: Tabs: [Tab(icon: icon (Icons. Cake), text: 'left '), Tab(icon: Icon(Icons. Golf_course), text: 'right '),], controller: TabController(length: 2, vsync: this),)))]; } Widget _itemBuilder(BuildContext context, int index) { return ListTile( leading: Icon(Icons.android), title: Text(' peerless title +$index'),); } } class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { _SliverAppBarDelegate(this._tabBar); final TabBar _tabBar; @override double get minExtent => _tabBar.preferredSize.height; @override double get maxExtent => _tabBar.preferredSize.height; @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent) { return Container( child: _tabBar, ); } @override bool shouldRebuild(_SliverAppBarDelegate oldDelegate) { return false; }}Copy the code
Effect:
That’s an obvious improvement, but how do we keep the TabBar in this SliverPersistentHeader from scrolling through the ListView?
The SliverPersistentHeader constructor is pinned to the data side because the SliverPersistentHeader and the SliverAppBar remain pinned to the data side. Set it to true and it will stop following the ListView once it gets to the top.
github