Skip to content

Latest commit

 

History

History
540 lines (442 loc) · 16.6 KB

08.flutter sliverappbar.md

File metadata and controls

540 lines (442 loc) · 16.6 KB

flutter SliverAppbar 控件介绍

一、使用方法

  • 与CustomScrollView、NestedScrollView集成的材质设计应用栏。应用栏由工具栏和其他小部件组成,例如 TabBar和FlexibleSpaceBar。应用栏通常会使用IconButton公开一个或多个常见操作,后者可选地后跟 PopupMenuButton以进行不太常见的操作

    image

  • 构造函数

const SliverAppBar({
    Key key,
    this.leading,         //在标题左侧显示的一个控件,在首页通常显示应用的 logo;在其他界面通常显示为返回按钮
    this.automaticallyImplyLeading = true,//? 控制是否应该尝试暗示前导小部件为null
    this.title,               //当前界面的标题文字
    this.actions,          //一个 Widget 列表,代表 Toolbar 中所显示的菜单,对于常用的菜单,通常使用 IconButton 来表示;对于不常用的菜单通常使用 PopupMenuButton 来显示为三个点,点击后弹出二级菜单
    this.flexibleSpace,        //一个显示在 AppBar 下方的控件,高度和 AppBar 高度一样, // 可以实现一些特殊的效果,该属性通常在 SliverAppBar 中使用
    this.bottom,         //一个 AppBarBottomWidget 对象,通常是 TabBar。用来在 Toolbar 标题下面显示一个 Tab 导航栏
    this.elevation,            //阴影
    this.forceElevated = false, 
    this.backgroundColor,       //APP bar 的颜色,默认值为 ThemeData.primaryColor。改值通常和下面的三个属性一起使用
    this.brightness,   //App bar 的亮度,有白色和黑色两种主题,默认值为 ThemeData.primaryColorBrightness
    this.iconTheme,  //App bar 上图标的颜色、透明度、和尺寸信息。默认值为 ThemeData().primaryIconTheme
    this.textTheme,    //App bar 上的文字主题。默认值为 ThemeData().primaryTextTheme
    this.primary = true,  //此应用栏是否显示在屏幕顶部
    this.centerTitle,     //标题是否居中显示,默认值根据不同的操作系统,显示方式不一样,true居中 false居左
    this.titleSpacing = NavigationToolbar.kMiddleSpacing,//横轴上标题内容 周围的间距
    this.expandedHeight,     //展开高度
    this.floating = false,       //是否随着滑动隐藏标题
    this.pinned = false,  //是否固定在顶部
    this.snap = false,   //与floating结合使用
  })

二、常用属性

  1. 在标题前面显示的一个控件,在首页通常显示应用的logo;在其他界面通常显示为返回按钮
        leading: Icon(_selectedChoice.icon) ,
  1. 控制是否应该尝试暗示前导小部件为null
        automaticallyImplyLeading:true ,
  1. 当前界面的标题文字
        title: Text(_selectedChoice.title )
  1. 一个 Widget 列表,代表 Toolbar 中所显示的菜单,对于常用的菜单,通常使用 IconButton 来表示;对于不常用的菜单通常使用 PopupMenuButton 来显示为三个点,点击后弹出二级菜单
          actions: <Widget>[
            new IconButton( // action button
              icon: new Icon(choices[0].icon),
              onPressed: () { _select(choices[0]); },
            ),
            new IconButton( // action button
              icon: new Icon(choices[1].icon),
              onPressed: () { _select(choices[1]); },
            ),
            new PopupMenuButton<Choice>( // overflow menu
              onSelected: _select,
              itemBuilder: (BuildContext context) {
                return choices.skip(2).map((Choice choice) {
                  return new PopupMenuItem<Choice>(
                    value: choice,
                    child: new Text(choice.title),
                  );
                }).toList();
              },
            )
          ],
  1. 一个显示在 AppBar 下方的控件,高度和 AppBar 高度一样,可以实现一些特殊的效果,该属性通常在 SliverAppBar 中使用
//        flexibleSpace: Container(
//          color: Colors.blue,
//          width: MediaQuery.of(context).size.width,
//          child: Text("aaaaaaaaaa"),
//          height: 10,
//        )
  1. 一个 AppBarBottomWidget 对象,通常是 TabBar。用来在 Toolbar 标题下面显示一个 Tab 导航栏
          bottom: new TabBar(
            isScrollable: true,
            tabs: choices.map((Choice choice) {
              return new Tab(
                text: choice.title,
                icon: new Icon(choice.icon),
              );
            }).toList(),
          ) 
  1. 材料设计中控件的 z 坐标顺序,默认值为 4,对于可滚动的 SliverAppBar, 当 SliverAppBar 和内容同级的时候,该值为 0, 当内容滚动 SliverAppBar 变为 Toolbar 的时候,修改 elevation 的值
            elevation: 1
  1. APP bar 的颜色,默认值为 ThemeData.primaryColor。改值通常和下面的三个属性一起使用
          backgroundColor: Colors.red,

  1. App bar 的亮度,有白色和黑色两种主题,默认值为 ThemeData.primaryColorBrightness
          brightness:Brightness.light ,

  1. App bar 上图标的颜色、透明度、和尺寸信息。默认值为 ThemeData().primaryIconTheme
          iconTheme: ThemeData().iconTheme,

  1. App bar 上的文字主题。默认值为 ThemeData().primaryTextTheme
          textTheme: ThemeData().accentTextTheme,

  1. 此应用栏是否显示在屏幕顶部
          primary: true,

  1. 标题是否居中显示,默认值根据不同的操作系统,显示方式不一样,true居中 false居左
          centerTitle: true,

  1. 横轴上标题内容 周围的间距
          titleSpacing: NavigationToolbar.kMiddleSpacing,

  1. 顶部的工具栏部分的透明度 <=1.0
          toolbarOpacity:1.0,

  1. bottom的工具栏部分的透明度 <=1.0
          bottomOpacity: 0.5,

  1. appbar是否随着滑动隐藏标题
          floating: true,
  1. tab 是否固定在顶部
           pinned: true,
  1. 与floating结合使用,如果snap和floating为true,则浮动应用栏将“捕捉”到视图中
            snap: true,

三、一个完整的例子

1、与NestedScrollView 集成SliverAppBar

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
        length: choices.length,
        child: Scaffold(
            body: NestedScrollView(
              headerSliverBuilder: _headerSliverBuilder,
              body : TabBarView(
                children: choices.map((Choice choice) {
                  return new Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: new ChoiceCard(choice: choice),
                  );
                }).toList(),
              ),
            )
        )
    );
  }

2、与CustomScrollView 集成SliverAppBar

  //例子2
  @override
  Widget build(BuildContext context) {
    return  Scaffold(
      body:CustomScrollView(
        slivers: <Widget>[
          const SliverAppBar(
            pinned: true,
            expandedHeight: 250.0,
            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: 20,
            ),
          ),
          SliverFixedExtentList(
            itemExtent: 50.0,
            delegate: SliverChildBuilderDelegate(
                  (BuildContext context, int index) {
                return Container(
                  alignment: Alignment.center,
                  color: Colors.lightBlue[100 * (index % 9)],
                  child: Text('list item $index'),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
  1. 一个完整的例子
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget{

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Text Demo',
      theme: ThemeData(
          primarySwatch: Colors.green
      ),
      home: MyHomePage(title: 'Text Demo'),
    );
  }
}


class MyHomePage extends StatefulWidget {

  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>{

  Choice _selectedChoice = choices[0]; // The app's "state".

  void _select(Choice choice) {
    setState(() { // Causes the app to rebuild with the new _selectedChoice.
      _selectedChoice = choice;
    });
  }

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
        length: choices.length,
        child: Scaffold(
            body: NestedScrollView(
              headerSliverBuilder: _headerSliverBuilder,
              body : TabBarView(
                children: choices.map((Choice choice) {
                  return new Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: new ChoiceCard(choice: choice),
                  );
                }).toList(),
              ),
            )
        )
    );
  }

  List<Widget> _headerSliverBuilder(BuildContext context, bool innerBoxIsScrolled){
    return <Widget>[
    SliverAppBar(

      //1.在标题左侧显示的一个控件,在首页通常显示应用的 logo;在其他界面通常显示为返回按钮
      leading: Icon(_selectedChoice.icon) ,

      //2. ? 控制是否应该尝试暗示前导小部件为null
      automaticallyImplyLeading:true ,

      //3.当前界面的标题文字
      title: Text(_selectedChoice.title ),

      //4.一个 Widget 列表,代表 Toolbar 中所显示的菜单,对于常用的菜单,通常使用 IconButton 来表示;
      //对于不常用的菜单通常使用 PopupMenuButton 来显示为三个点,点击后弹出二级菜单
      actions: <Widget>[
        new IconButton( // action button
          icon: new Icon(choices[0].icon),
          onPressed: () { _select(choices[0]); },
        ),
        new IconButton( // action button
          icon: new Icon(choices[1].icon),
          onPressed: () { _select(choices[1]); },
        ),
        new PopupMenuButton<Choice>( // overflow menu
          onSelected: _select,
          itemBuilder: (BuildContext context) {
            return choices.skip(2).map((Choice choice) {
              return new PopupMenuItem<Choice>(
                value: choice,
                child: new Text(choice.title),
              );
            }).toList();
          },
        )
      ],

      //5.一个显示在 AppBar 下方的控件,高度和 AppBar 高度一样,
      // 可以实现一些特殊的效果,该属性通常在 SliverAppBar 中使用
        flexibleSpace: FlexibleSpaceBar(
          centerTitle: true,
          background: Image(
              image: NetworkImage("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1551944816841&di=329f747e3f4c2554f24c609fd6f77c49&imgtype=0&src=http%3A%2F%2Fimg.tupianzj.com%2Fuploads%2Fallimg%2F160610%2F9-160610114520.jpg"),
              fit: BoxFit.cover,
          ),
        ),

      //6.一个 AppBarBottomWidget 对象,通常是 TabBar。用来在 Toolbar 标题下面显示一个 Tab 导航栏
      bottom: new TabBar(
        isScrollable: true,
        tabs: choices.map((Choice choice) {
          return new Tab(
            text: choice.title,
            icon: new Icon(choice.icon),
          );
        }).toList(),
      ) ,

      //7.? 材料设计中控件的 z 坐标顺序,默认值为 4,对于可滚动的 SliverAppBar,
      // 当 SliverAppBar 和内容同级的时候,该值为 0, 当内容滚动 SliverAppBar 变为 Toolbar 的时候,修改 elevation 的值
      elevation: 1,

      //APP bar 的颜色,默认值为 ThemeData.primaryColor。改值通常和下面的三个属性一起使用
      backgroundColor: Colors.red,

      //App bar 的亮度,有白色和黑色两种主题,默认值为 ThemeData.primaryColorBrightness
      brightness:Brightness.light ,

      //App bar 上图标的颜色、透明度、和尺寸信息。默认值为 ThemeData().primaryIconTheme
      iconTheme: ThemeData().primaryIconTheme,

      //App bar 上的文字主题。默认值为 ThemeData().primaryTextTheme
      textTheme: ThemeData().accentTextTheme,

      //此应用栏是否显示在屏幕顶部
      primary: true,

      //标题是否居中显示,默认值根据不同的操作系统,显示方式不一样,true居中 false居左
      centerTitle: true,

      //横轴上标题内容 周围的间距
      titleSpacing: NavigationToolbar.kMiddleSpacing,

      //展开高度
      expandedHeight: 200,

      //是否随着滑动隐藏标题
      floating: true,

      //tab 是否固定在顶部
      pinned: true,

      //与floating结合使用
      snap: true,

    )
    ];
  }


//  //例子2
//  @override
//  Widget build(BuildContext context) {
//    return  Scaffold(
//      body:CustomScrollView(
//        slivers: <Widget>[
//          const SliverAppBar(
//            pinned: true,
//            expandedHeight: 250.0,
//            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: 20,
//            ),
//          ),
//          SliverFixedExtentList(
//            itemExtent: 50.0,
//            delegate: SliverChildBuilderDelegate(
//                  (BuildContext context, int index) {
//                return Container(
//                  alignment: Alignment.center,
//                  color: Colors.lightBlue[100 * (index % 9)],
//                  child: Text('list item $index'),
//                );
//              },
//            ),
//          ),
//        ],
//      ),
//    );
//  }
}




class Choice {
  const Choice({ this.title, this.icon });
  final String title;
  final IconData icon;
}

const List<Choice> choices = const <Choice>[
  const Choice(title: 'Car', icon: Icons.directions_car),
  const Choice(title: 'Bicycle', icon: Icons.directions_bike),
  const Choice(title: 'Boat', icon: Icons.directions_boat),
  const Choice(title: 'Bus', icon: Icons.directions_bus),
  const Choice(title: 'Train', icon: Icons.directions_railway),
  const Choice(title: 'Walk', icon: Icons.directions_walk),
];

class ChoiceCard extends StatelessWidget {
  const ChoiceCard({ Key key, this.choice }) : super(key: key);

  final Choice choice;

  @override
  Widget build(BuildContext context) {
    final TextStyle textStyle = Theme.of(context).textTheme.display1;

    Widget _itemBuilder(BuildContext context,int index){
      return ListTile(
        leading: Icon(choice.icon),
        title: Text("this is a " + choice.title),
      );
    }

    return new Card(
      color: Colors.white,
      child: Center(
        child: ListView.builder(
            itemBuilder: _itemBuilder,
            itemCount: 30,
        ),
      ),
//          body: Center(
//            child: ListView.builder(
//                itemBuilder: _itemBuilder,
//                itemCount: 100,
//
//            ),
//          )),

//      child: new Center(
//        child: new Column(
//          mainAxisSize: MainAxisSize.min,
//          crossAxisAlignment: CrossAxisAlignment.center,
//          children: <Widget>[
//            new Icon(choice.icon, size: 128.0, color: textStyle.color),
//            new Text(choice.title, style: textStyle),
//          ],
//        ),
//      ),
    );
  }
}