Flutter 系列文章:Flutter SliverAppbar 控制元件介紹

sometime-rock發表於2019-03-19

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),
//          ],
//        ),
//      ),
    );
  }
}




複製程式碼

相關文章