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