flutter-widget-AppBar与SliverAppBar

2,546 阅读5分钟

APPBar:应用栏,它通常应用于Scaffold.appBar属性,该属性将应用栏放置在屏幕顶部的固定高度小部件中,对于可滚动的应用栏可查看SliverAppBar,它将Appbar嵌入到sliver中以便在CustomScrollView中使用。应用栏由工具栏组成,或者是工具栏和其他widget组合形式,例如tabBar和FlexibleSpaceBar。先看看它的属性

AppBar({
  Key key,
  this.leading,
  this.automaticallyImplyLeading = true,
  this.title,
  this.actions,
  this.flexibleSpace,
  this.bottom,
  this.elevation = 4.0,
  this.backgroundColor,
  this.brightness,
  this.iconTheme,
  this.textTheme,
  this.primary = true,
  this.centerTitle,
  this.titleSpacing = NavigationToolbar.kMiddleSpacing,
  this.toolbarOpacity = 1.0,
  this.bottomOpacity = 1.0,
})

leading:显示在[title]前面的小部件。如果该值为null,并且[automaticallyImplyLeading]设置为true,则[AppBar]将暗示一个适当的小部件。 例如,如果[AppBar]位于也具有[Drawer]的[Scaffold]中,则[Scaffold]将用打开抽屉的[IconButton]填充此小部件(使用[Icons.menu])。 如果没有[抽屉]并且父级[导航器]可以返回,则[AppBar]将使用调用[Navigator.maybePop]的[BackButton]。 以下代码显示了如何手动指定抽屉按钮而不是依靠[automaticallyImplyLeading]:

AppBar(
///   leading: Builder(
///     builder: (BuildContext context) {
///       return IconButton(
///         icon: const Icon(Icons.menu),
///         onPressed: () { Scaffold.of(context).openDrawer(); },
///         tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
///       );
///     },
///   ),
/// )

title:一般是一个Text widget,显示标题

actions:显示在title后的widget,一般为IconButtons,一般把不常用的放到popupMenuButton中,并把它作为最后一个action。

flexibleSpace: 通常为[FlexibleSpaceBar],该小部件堆叠在工具栏和选项卡的后面。 它的高度将与应用栏的整体高度相同。除非[AppBar]的容器更改了[AppBar]的大小,否则灵活的空间实际上并不灵活。 [CustomScrollView]中的[SliverAppBar]滚动时会更改[AppBar]的高度。 有关详细信息,请参见[FlexibleSpaceBar]。通常用在SliverAPPBar中。

bottom:显示在应用栏的底部。通常为TabBar,除此之外这个属性的内容只能是实现了PreferredSizeWidget的widget才可以。

primary:此应用栏是否显示在屏幕顶部。如果为true,则应用栏的工具栏元素和[底部]小部件将在顶部填充系统状态栏的高度。 [flexibleSpace]的布局不受[primary]属性的影响。示例代码如下

class AppBarDemo extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _AppBarDemoState();
  }
}

class _AppBarDemoState extends State<AppBarDemo> with SingleTickerProviderStateMixin{
  TabController _tabController;
  ScrollController _scrollViewController;
  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 6, vsync: this);
    _scrollViewController =  ScrollController();

  }

  @override
  void dispose() {
    _tabController.dispose();
    _scrollViewController.dispose();
    super.dispose();

  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("AppBarDemo"),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.home),
            onPressed: () {},
          ),
          IconButton(
            icon: Icon(Icons.access_alarm),
            onPressed: () {},
          ),
          PopupMenuButton(
            initialValue: "first",
            child: Icon(Icons.more_horiz),
            itemBuilder: (BuildContext context)=> <PopupMenuEntry>[
              PopupMenuItem(
                  value: "first", child: Text("This is the firstItem")),
              PopupMenuItem(
                  value: "second", child: Text("This is the secondItem"))]
            ,
          )
        ],
//        flexibleSpace: FlexibleSpaceBar(
//            centerTitle: true,
//            title: Text("flexibleSpace",
//                style: TextStyle(
//                  color: Colors.white,
//                  fontSize: 16.0,
//                )),
//            background: Image.network(
//              "https://images.pexels.com/photos/396547/pexels-photo-396547.jpeg?auto=compress&cs=tinysrgb&h=350",
//              fit: BoxFit.cover,
//
//              /// 色彩叠加  UI可以理解为两个色彩涂层,在图片混合一个色层
//              // color: Colors.redAccent,  //混合的颜色
//              // colorBlendMode: BlendMode.darken,  //混合方式
//
//              ///图片重复填充容器
//              // repeat: ImageRepeat.repeat,
//            )),
        bottom: TabBar(
          isScrollable: true,
          controller: _tabController,
          tabs: <Widget>[
          Tab(text: "Tabs 1"),
          Tab(text: "Tabs 2"),
          Tab(text: "Tabs 3"),
          Tab(text: "Tabs 4"),
          Tab(text: "Tabs 5"),
          Tab(text: "Tabs 6"),
        ],),
        primary: true,
      ),
    );
  }
}

效果为

primary为false的效果如下

通过图可以看到,这个属性影响其实挺大的,true时不会被遮挡。

SliverAppBar:它与AppBar都是继承自StatefulWidget,都代表Toolbar,它的构造方法与Appbar基本相同,但他却不能直接使用,他通常与ScrollView一起使用。他们二者的区别在于AppBar位置固定,SliverAppBar是可以跟随内容滚动的。下面我们将其放入NestScrollView中

class SliverAppBarDemo extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _SliverAppBarDemoState();
  }
}

class _SliverAppBarDemoState extends State<SliverAppBarDemo> {
  final List<ListItem> listData = [];

  @override
  void initState() {
    super.initState();
    for (int i = 0; i < 20; i++) {
      listData.add(ListItem("我是测试标题$i", Icons.cake));
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body:NestedScrollView(
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            SliverAppBar(
              leading:IconButton(icon: Icon(Icons.arrow_back), onPressed: (){}),// 在标题前面显示的一个控件,在首页通常显示应用的 logo;在其他界面通常显示为返回按钮
              //title, // Toolbar 中主要内容,通常显示为当前界面的标题文字
              //actions, // 一个 Widget 列表,代表 Toolbar 中所显示的菜单,对于常用的菜单,通常使用 IconButton 来表示;对于不常用的菜单通常使用 PopupMenuButton 来显示为三个点,点击后弹出二级菜单
              //flexibleSpace,
              //bottom,         //底部内容区域
              //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,     //标题是否居中, 标题是否居中显示,默认值根据不同的操作系统,显示方式不一样
              primary: true,
              //是否预留高度
              forceElevated: false,
              automaticallyImplyLeading: true,
              titleSpacing: NavigationToolbar.kMiddleSpacing,
              snap: false,
              //与floating结合使用
              expandedHeight: 200.0,
              //展开高度
              floating: false,
              //是否随着滑动隐藏标题
              pinned: true,
              //是否固定在顶部
              flexibleSpace: FlexibleSpaceBar(
                //可以展开区域,通常是一个FlexibleSpaceBar
                  centerTitle: true,
                  title: Text("我是一个帅气的标题",
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 16.0,
                      )),
                  background: Image.network(
                    //"http://h.hiphotos.baidu.com/image/pic/item/342ac65c103853434cc02dda9f13b07eca80883a.jpg",
                    "http://b.zol-img.com.cn/desk/bizhi/image/6/960x600/1432800027589.jpg",
                    //"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.fill,
                  )),
            )
          ];
        },
        body: Center(
          child: ListView.builder(
            shrinkWrap: true,
            itemBuilder: (BuildContext context, int index) {
              return ListItemWidget(listData[index]);
            },
            itemCount: listData.length,
          ),
        ),
      ) ,
    );
  }
}

class ListItem {
  final String title;
  final IconData iconData;

  ListItem(this.title, this.iconData);
}

class ListItemWidget extends StatelessWidget {
  final ListItem listItem;

  ListItemWidget(this.listItem);

  @override
  Widget build(BuildContext context) {
    return InkWell(
      child: ListTile(
        leading: Icon(listItem.iconData),
        title: Text(listItem.title),
      ),
      onTap: () {},
    );
  }
}

效果为

随着滑动会产生如Android中的collapsingToolbar的效果,同样上述代码中加入了flexibleSpaceBar。