flutter SliverAppbar 控制元件介紹
一、使用方法
-
與CustomScrollView、NestedScrollView整合的材質設計應用欄。應用欄由工具欄和其他小部件組成,例如 TabBar和FlexibleSpaceBar。應用欄通常會使用IconButton公開一個或多個常見操作,後者可選地後跟 PopupMenuButton以進行不太常見的操作
-
建構函式
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結合使用
})
複製程式碼
二、常用屬性
- 在標題前面顯示的一個控制元件,在首頁通常顯示應用的logo;在其他介面通常顯示為返回按鈕
leading: Icon(_selectedChoice.icon) ,
複製程式碼
- 控制是否應該嘗試暗示前導小部件為null
automaticallyImplyLeading:true ,
複製程式碼
- 當前介面的標題文字
title: Text(_selectedChoice.title )
複製程式碼
- 一個 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();
},
)
],
複製程式碼
- 一個顯示在 AppBar 下方的控制元件,高度和 AppBar 高度一樣,可以實現一些特殊的效果,該屬性通常在 SliverAppBar 中使用
// flexibleSpace: Container(
// color: Colors.blue,
// width: MediaQuery.of(context).size.width,
// child: Text("aaaaaaaaaa"),
// height: 10,
// )
複製程式碼
- 一個 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(),
)
複製程式碼
- 材料設計中控制元件的 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().iconTheme,
複製程式碼
- App bar 上的文字主題。預設值為 ThemeData().primaryTextTheme
textTheme: ThemeData().accentTextTheme,
複製程式碼
- 此應用欄是否顯示在螢幕頂部
primary: true,
複製程式碼
- 標題是否居中顯示,預設值根據不同的作業系統,顯示方式不一樣,true居中 false居左
centerTitle: true,
複製程式碼
- 橫軸上標題內容 周圍的間距
titleSpacing: NavigationToolbar.kMiddleSpacing,
複製程式碼
- 頂部的工具欄部分的透明度 <=1.0
toolbarOpacity:1.0,
複製程式碼
- bottom的工具欄部分的透明度 <=1.0
bottomOpacity: 0.5,
複製程式碼
- appbar是否隨著滑動隱藏標題
floating: true,
複製程式碼
- tab 是否固定在頂部
pinned: true,
複製程式碼
- 與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'),
);
},
),
),
],
),
);
}
複製程式碼
- 一個完整的例子
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),
// ],
// ),
// ),
);
}
}
複製程式碼