A material design app bar that integrates with a [CustomScrollView].android
AppBar 和 SliverAppBar 是Material Design中的 App Bar,也就是 Android 中的 Toolbargit
SliverAppBar是一个与 CustomScrollView 结合使用的material design
风格的标题栏 .github
不一样于AppBar, 它能够展开或收缩.markdown
构造方法:app
const SliverAppBar({
Key key,
this.leading, //左侧标题
this.automaticallyImplyLeading = true, //若是leading为null,是否自动填充一个leading
this.title, //标题
this.actions, //菜单
this.flexibleSpace, //能够展开区域,一般是一个FlexibleSpaceBar
this.bottom, //底部内容区域
this.elevation,
this.forceElevated = false, //结合 elevation 使用,当elevation 不为 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, //展开后的高度
this.floating = false, //是否向下滑动时当即显示appBar
this.pinned = false, //appBar是否置顶
this.snap = false, //当手指放开时,SliverAppBar是否会根据当前的位置展开/收起
this.stretch = false,
this.stretchTriggerOffset = 100.0,
this.onStretchTrigger,
this.shape,
})
复制代码
若是你看过AppBar的构造方法,那么你会发现AppBar的构造方法都是在这里面的。其属性也是一致的,下面咱们针对公共的属性作一下详细的解释:less
snap : 须要注意的是snap
是和floading
结合使用的 , 而且要求floating=true
, 不然使用会报错.ide
automaticallyImplyLeading : 若是为true(默认) , 那么页面能够回退的话,会添加一个返回按钮.oop
leading:在标题前面显示的一个控件,在首页一般显示应用的 logo;在其余界面一般显示为返回按钮flex
title: Toolbar 中主要内容,一般显示为当前界面的标题文字ui
actions:一个 Widget 列表,表明 Toolbar 中所显示的菜单,对于经常使用的菜单,一般使用 IconButton 来表示;对于不经常使用的菜单一般使用 PopupMenuButton 来显示为三个点,点击后弹出二级菜单
bottom:一个 AppBarBottomWidget 对象,一般是 TabBar。用来在 Toolbar 标题下面显示一个 Tab 导航栏
elevation:纸墨设计中控件的 z 坐标顺序,默认值为 4,对于可滚动的 SliverAppBar,当 SliverAppBar 和内容同级的时候,该值为 0, 当内容滚动 SliverAppBar 变为 Toolbar 的时候,修改 elevation 的值 flexibleSpace:一个显示在 AppBar 下方的控件,高度和 AppBar 高度同样,能够实现一些特殊的效果,该属性一般在 SliverAppBar 中使用
backgroundColor:APP bar 的颜色,默认值为 ThemeData.primaryColor。改值一般和下面的三个属性一块儿使用
brightness:App bar 的亮度,有白色和黑色两种主题,默认值为 ThemeData.primaryColorBrightness
iconTheme:App bar 上图标的颜色、透明度、和尺寸信息。默认值为 ThemeData.primaryIconTheme
textTheme: App bar 上的文字样式。默认值为 ThemeData.primaryTextTheme
centerTitle: 标题是否居中显示,默认值根据不一样的操做系统,显示方式不同
一个简单的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,
),
//标题是否居中
centerTitle: false,
//标题间距
//titlePadding: EdgeInsetsDirectional.only(start: 0, bottom: 16),
collapseMode: CollapseMode.parallax,
))
复制代码
虽然基本相同,构造方法也是很是的简单,可是咱们却不能直接使用它,由官方文档能够看到咱们一般结合ScrollView来使用它。
咱们结合CustomScrollView来看下例子吧:
/*
* Created by 李卓原 on 2018/9/13.
* email: zhuoyuan93@gmail.com
*
*/
import 'package:flutter/material.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, //标题居中
expandedHeight: 200.0, //展开高度200
floating: false, //不随着滑动隐藏标题
pinned: true, //固定在顶部
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
title: Text('我是一个FlexibleSpaceBar'),
background: Image.network(
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531798262708&di=53d278a8427f482c5b836fa0e057f4ea&imgtype=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('无与伦比的标题+$index'),
);
}
}
复制代码
首先咱们使用了NestedScrollView中的headerSliverBuilder属性添加了SliverAppBar
而后咱们设置展开的高度为200,不让标题栏随着滑动滚动出可视区域, 最后咱们给NestedScrollView的body加了一个长度为15的ListView
而后咱们来看下效果:
咱们把 pinned的属性设置为false(不固定在顶部)再看下效果
接下来咱们来看下bottom属性,容许咱们在在下面放置你想放置其余Widget,好吧咱们来放个TabBar看下
其实代码很简单,只不过咱们须要让DiscoverListPage继承于 StatefulWidget,而后让State with TickerProviderStateMixin , 并为SliverAppBar添加个bottom ,改造后的代码 :
/*
* Created by 李卓原 on 2018/9/13.
* email: zhuoyuan93@gmail.com
*
*/
import 'package:flutter/material.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,
//展开高度200
expandedHeight: 200.0,
//不随着滑动隐藏标题
floating: false,
//固定在顶部
pinned: false,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
title: Text('我是一个FlexibleSpaceBar'),
background: Image.network(
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531798262708&di=53d278a8427f482c5b836fa0e057f4ea&imgtype=0&src=http%3A%2F%2Fh.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F342ac65c103853434cc02dda9f13b07eca80883a.jpg",
fit: BoxFit.cover,
),
),
// bottom 这是新增的 这是新增的 这是新增的 这是新增的
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.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('无与伦比的标题+$index'),
);
}
}
复制代码
看一下效果: 简直, 丑的不忍直视。 固然咱们是但愿这个TabBar在SliverAppBar下方,而且随着SliverAppBar滚动的。
因为TabBar的高度因此咱们并不能让SliverAppBar滑动到顶部,因此要想实现随着SliverAppBar的移动,把TabBar放在bottom也不是很合适的。 在这里,咱们能够借助于SliverPersistentHeader中的SliverPersistentHeader属性来解决
SliverPersistentHeader的构造很简单,只有简单的几个属性,再也不具体讲了
const SliverPersistentHeader({
Key key,
@required this.delegate,
this.pinned = false,
this.floating = false,
})
复制代码
所有代码以下:
/*
* Created by 李卓原 on 2018/9/13.
* email: zhuoyuan93@gmail.com
*
*/
import 'package:flutter/material.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,
//展开高度200
expandedHeight: 200.0,
//不随着滑动隐藏标题
floating: false,
//固定在顶部
pinned: false,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
title: Text('我是一个FlexibleSpaceBar'),
background: Image.network(
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531798262708&di=53d278a8427f482c5b836fa0e057f4ea&imgtype=0&src=http%3A%2F%2Fh.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F342ac65c103853434cc02dda9f13b07eca80883a.jpg",
fit: BoxFit.cover,
),
),
),
SliverPersistentHeader(
delegate: _SliverAppBarDelegate(TabBar(
labelColor: Colors.red,
unselectedLabelColor: Colors.grey,
tabs: [
Tab(icon: Icon(Icons.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('无与伦比的标题+$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;
}
}
复制代码
效果:
比刚才有了明显的进步,可是有童鞋就问了,咱们怎么让这个SliverPersistentHeader中的内容(TabBar)不随着ListView的滚动而滑动呢?
其实很简单,上面我贴出了SliverPersistentHeader的构造方法,由于SliverPersistentHeader跟SliverAppBar同样都有一个 pinned属性,将它设置为true这里面的内容就会在到达顶部后中止跟随ListView移动了。