前言
相信不少同學已經通過線上直播觀看了本週Google舉辦的Flutter Live 2018,在本次活動中Google正式釋出了Flutter 1.0版本,這對於正在學習Flutter或已經使用Flutter進行應用開發的我們都是一個好訊息,1.0版本中增加了一些新的特性,並且是目前最穩定的版本,沒有了解本次活動內容的同學可以通過如下連結檢視。
Flutter Live 2018舉辦後也在本週掀起了一波Flutter普及小熱潮,本公眾號將一如既往的給大家分享學習Flutter過程的心得體會、經驗總結和開發實戰。希望給初學Flutter的同學一點兒幫助,同時也可以和正在使用Flutter進行應用開發的同學一起交流學習。
話不多說,下面我們進入本篇主題。上一篇文章給大家分享了一部分Flutter日常開發中常用的Widget和其屬性的使用介紹,其中包括文字、圖片、按鈕、輸入控制元件和選擇控制元件等,這些都是應用開發中最基本的UI展示控制元件,接下來我們將繼續向大家詳細介紹其他一些常用Widget。
常用Widget介紹
日期、時間選擇器和通用選擇器
選擇器對應的Widget在Flutter中也有兩種風格的實現,具體用法和使用例子如下。
Material design風格的日期選擇器
showDatePicker(
context: context,
initialDate: DateTime.parse("20181209"), //初始選中日期
firstDate: DateTime.parse("20181109"), //可選日期範圍第一個日期
lastDate: DateTime.parse("20190109"), //可選日期範圍最後一個日期
selectableDayPredicate: (dateTime) { //通過此方法可以過濾掉可選範圍內不可選的特定日期
if(dateTime.day == 10 || dateTime.day == 20 || dateTime.day == 30) {
//此處表示10號、20號、30號不可選
return false;
}
return true;
},
initialDatePickerMode: DatePickerMode.day, //初始化選擇模式,有day和year兩種
).then((dateTime) { //選擇日期後點選OK拿到的日期結果
print('當前選擇了:${dateTime.year}年${dateTime.month}月${dateTime.day}日');
});
複製程式碼
顯示效果如下圖:
Material design風格的時間選擇器
showTimePicker(
context: context,
initialTime: TimeOfDay.now(), //初始化顯示時間
).then((timeOfDay) { //選擇時間後點選OK拿到的時間結果
if(timeOfDay == null) {
return;
}
print('當前選擇了:${timeOfDay.hour}時${timeOfDay.minute}分');
});
複製程式碼
顯示效果如下圖:
Cupertino風格的日期選擇器CupertinoDatePicker
CupertinoDatePicker(
mode: CupertinoDatePickerMode.date, //日期時間模式,此處為日期模式
onDateTimeChanged: (dateTime) { //日期改變時呼叫的方法
if (dateTime == null) {
return;
}
print('當前選擇了:${dateTime.year}年${dateTime.month}月${dateTime.day}日');
},
initialDateTime: DateTime.now(), //初始化展示時的日期時間
minimumYear: 2018, //最小年份,只有mode為date時有效
maximumYear: 2019, //最大年份,只有mode為date時有效
),
CupertinoDatePicker(
mode: CupertinoDatePickerMode.dateAndTime, //日期時間模式,此處為日期和時間模式
onDateTimeChanged: (dateTime) {
if (dateTime == null) {
return;
}
print('當前選擇了:${dateTime.year}年${dateTime.month}月${dateTime.day}日 ${dateTime.hour}時${dateTime.minute}分${dateTime.second}秒');
},
initialDateTime: DateTime.now(),
minimumDate: DateTime.parse("20181109"), //最小日期時間,只有mode為dateAndTime時有效
maximumDate: DateTime.parse("20190109"), //最大日期時間,只有mode為dateAndTime時有效
use24hFormat: false, // 是否使用24小時格式,此處不使用,則選擇時可以選擇AM和PM值
),
CupertinoDatePicker(
mode: CupertinoDatePickerMode.time, //日期時間模式,此處為時間模式
onDateTimeChanged: (dateTime) {
if (dateTime == null) {
return;
}
print('當前選擇了:${dateTime.hour}時${dateTime.minute}分${dateTime.second}秒');
},
initialDateTime: DateTime.now(),
use24hFormat: true, // 是否使用24小時格式,此處使用
),
複製程式碼
顯示效果如下圖:
Cupertino風格的時間選擇器CupertinoTimerPicker
CupertinoTimerPicker(
mode: CupertinoTimerPickerMode.hms, //可以設定時分、時分秒和分秒三種模式
initialTimerDuration: Duration(hours: 1, minutes: 35, seconds: 50), // 預設顯示的時間值
minuteInterval: 5, // 分值間隔,必須能夠被initialTimerDuration.inMinutes整除
secondInterval: 10, // 秒值間隔,必須能夠被initialTimerDuration.inSeconds整除,此時設定為10,則選擇項為0、10、20、30、40、50六個值
onTimerDurationChanged: (duration) {
print('當前選擇了:${duration.inHours}時${duration.inMinutes-duration.inHours*60}分${duration.inSeconds-duration.inMinutes*60}秒');
},
)
複製程式碼
顯示效果如下圖:
Cupertino風格的通用選擇器CupertinoPicker
CupertinoPicker(
backgroundColor: Colors.white, //選擇器背景色
itemExtent: 30, //item的高度
onSelectedItemChanged: (index) { //選中item的位置索引
print("index = $index}");
},
children: <Widget>[ //所有的選擇項
Text('Apple'),
Text('Banana'),
Text('Orange'),
],
)
複製程式碼
顯示效果如下圖:
常用彈框和資訊提示浮層
常見的彈框主要包含Material design風格的SimpleDialog、AlertDialog、BottomSheet等,和Cupertino風格的CupertinoDialog、CupertinoAlertDialog、CupertinoActionSheet等。
SimppleDialog和AlertDialog
SimpleDialog和AlertDialog本身都是一個Widget,使用時需要通過showDialog方法來展示。
// 展示SimpleDialog
showDialog( //展示Dialog的方法
context: context,
builder: (context) {
return SimpleDialog(
title: Text('評價一下'), //標題
titlePadding: EdgeInsets.all(20), //標題的padding值
children: <Widget>[ //彈框中的選項
SimpleDialogOption( //每一個選項都是一個SimpleDialogOption Widget
onPressed: (){
print('給個好評');
Navigator.pop(context);
},
child: Text('給好評'), //選項提示文案
),
SimpleDialogOption(
onPressed: (){
print('殘忍拒絕');
Navigator.pop(context);
},
child: Text('殘忍拒絕'),
),
SimpleDialogOption(
onPressed: (){
print('我有意見');
Navigator.pop(context);
},
child: Text('我有意見'),
),
],
contentPadding: EdgeInsets.all(0),
);
},
);
//展示AlertDialog
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('提示'), //標題
titlePadding: EdgeInsets.all(20), //標題的padding值
content: Text('是否想放棄學習Flutter'), //彈框展示主要內容
contentPadding: EdgeInsets.only(left: 20, right: 20), //內容的padding值
actions: <Widget>[ //操作按鈕陣列
FlatButton(
onPressed: () {
print("取消");
Navigator.pop(context);
},
child: Text('取消'),
),
FlatButton(
onPressed: () {
print('確定');
Navigator.pop(context);
},
child: Text('確定'),
),
],
);
},
);
複製程式碼
顯示效果如下圖:
永續性BottomSheet和模態BottomSheet
BottomSheet一般不會直接建立,通常是通過ScaffoldState.showBottomSheet方法來建立永續性BottomSheet,通過showModalBottomSheet方法來建立模態BottomSheet。
// 建立永續性BottomSheet
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey, //設定key值以便獲取ScaffoldState
appBar: AppBar(
title: Text(widget.title),
),
body: _buildBottomSheet(context)
);
}
Widget _buildBottomSheet(BuildContext context) {
return Container(
child: RaisedButton(
child: Text("BottomSheet"),
onPressed: () {
print("彈出BottomSheet");
//通過獲取當前ScaffoldState來展示BottomSheet
_scaffoldKey.currentState.showBottomSheet<void>((context){
return Container(
decoration: BoxDecoration(
border: Border(top: BorderSide(color: Colors.grey))
),
child: Padding(
padding: const EdgeInsets.all(20),
child: Text('This is a Material persistent bottom sheet. Drag downwards to dismiss it.',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.blueAccent,
fontSize: 22
)
)
)
);
});
}
),
);
}
//建立模態BottomSheet
Widget _buildModalBottomSheet(BuildContext context) {
return Container(
child: RaisedButton(
child: Text("ModalBottomSheet"),
onPressed: () {
print("ModalBottomSheet");
//直接使用showModalBottomSheet方法建立模態BottomSheet
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
decoration: BoxDecoration(
border: Border(top: BorderSide(color: Colors.grey))
),
child: Padding(
padding: const EdgeInsets.all(20),
child: Text('This is a Material modal bottom sheet. Drag downwards to dismiss it.',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.blueAccent,
fontSize: 22
)
)
)
);
},
);
}
)
);
}
複製程式碼
顯示效果如下圖:
CupertinoAlertDialog
由於CupertinoDialog已經被標記為過時的Widget,這裡就只介紹CupertinoAlertDialog的用法。
showDialog( //通過showDialog方法展示alert彈框
context: context,
builder: (context) {
return CupertinoAlertDialog(
title: Text('提示'), //彈框標題
content: Text('是否想放棄學習Flutter'), //彈框內容
actions: <Widget>[ //操作控制元件
CupertinoDialogAction(
onPressed: () { //控制元件點選監聽
print("我不會放棄的");
Navigator.pop(context);
},
textStyle: TextStyle(fontSize: 18, color: Colors.blueAccent), //按鈕上的文字風格
child: Text('取消'), //控制元件顯示內容
),
CupertinoDialogAction(
onPressed: () {
print("我投降");
Navigator.pop(context);
},
textStyle: TextStyle(fontSize: 18, color: Colors.grey),
child: Text('確定'),
),
],
);
},
);
複製程式碼
顯示效果如下圖:
CupertinoActionSheet
該Widget通常作為子Widget傳遞給showCupertinoModalPopup方法,由該方法將其通過從螢幕底部向上滑動來顯示。
showCupertinoModalPopup(
context: context,
builder: (context) {
return CupertinoActionSheet(
title: Text('提示', style: TextStyle(fontSize: 22),), //標題
message: Text('麻煩抽出幾分鐘對該軟體進行評價,謝謝!'), //提示內容
actions: <Widget>[ //操作按鈕集合
CupertinoActionSheetAction(
onPressed: (){
Navigator.pop(context);
},
child: Text('給個好評'),
),
CupertinoActionSheetAction(
onPressed: (){
Navigator.pop(context);
},
child: Text('我要吐槽'),
),
],
cancelButton: CupertinoActionSheetAction( //取消按鈕
onPressed: () {
Navigator.pop(context);
},
child: Text('取消'),
),
);
},
);
複製程式碼
顯示效果如下圖:
導航欄和標籤欄
導航欄和標籤欄是頁面框架搭建常用的控制元件,Flutter中主要包含的對應Widget有Material design風格的BottomNavigationBar、Tabbar和Cupertino風格的CupertinoNavigationBar、CupertinoTabBar等等。
BottomNavigationBar
該Widget通常在Material design風格的頁面框架Widget Scaffold中使用,作為Scaffold的一個bottomNavigationBar屬性值。具體使用方法如下:
int selectedIndex = 1;
final widgetOptions = [
Text('This is Home Page'),
Text('This is Product Page'),
Text('This is More Page'),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar( //應用欄
title: Text(widget.title),
),
body: widgetOptions[selectedIndex], //頁面內容
bottomNavigationBar: BottomNavigationBar( //底部導航欄
items: <BottomNavigationBarItem>[ //導航欄選項集合
BottomNavigationBarItem( //底部單個導航欄選項
icon: Icon(Icons.home), //圖示
title: Text('首頁'), //標題
),
BottomNavigationBarItem(
icon: Icon(Icons.list),
title: Text('產品'),
),
BottomNavigationBarItem(
icon: Icon(Icons.more_horiz),
title: Text('更多'),
),
],
currentIndex: selectedIndex, //當前導航欄選中的索引
fixedColor: Colors.redAccent, //選中項的標題顏色
onTap: (index) { //導航欄項點選後的處理方法
setState(() {
selectedIndex = index;
});
},
),
);
}
複製程式碼
Tabbar
Tabbar通常建立為AppBar的AppBar.bottom部分,使用方式如下:
TabController _controller;
int _selectedIndex = 0;
final List<Widget> _tabViews = [
Container(
child: Text('This is hot page'),
),
Container(
child: Text('This is tech page'),
),
Container(
child: Text('This is financial page'),
),
];
final List<Tab> _tabs = [
Tab(
text: '熱門', //標題,和child不能同時存在,只能設定一個
// child: Text('熱門'), //標題,和text不能同時存在
icon: Icon(Icons.home), //標題對應的圖示
),
Tab(
text: '科技',
// child: Text('科技'),
icon: Icon(Icons.list),
),
Tab(
text: '金融',
// child: Text('金融'),
icon: Icon(Icons.more),
),
];
@override
void initState() {
super.initState();
_controller = TabController(vsync: this, length: _tabs.length);
_controller.addListener(_handleTabSelection);
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
_controller.dispose();
}
void _handleTabSelection() {
setState(() {
_selectedIndex = _controller.index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar( //應用欄
title: Text(widget.title),
bottom: TabBar(
controller: _controller, //TabBar控制器,通過給controller物件新增addListener方法來監聽切換動作
tabs: _tabs, //標籤欄顯示項集合
),
),
body: _tabViews[_selectedIndex], //頁面顯示的內容
);
}
複製程式碼
BottomNavigationBar和Tabbar顯示效果如下圖:
CupertinoNavigationBar
Cupertino風格的頂部導航欄,通常與CupertinoPageScaffold一起使用。
CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Center(child: Text('詳情', style: TextStyle(color: Colors.white),),), //導航欄中間控制元件
leading: Icon(Icons.arrow_back_ios, size: 18,), //導航欄左邊控制元件
trailing: Text('退出'), //導航欄右邊控制元件
backgroundColor: Colors.blueAccent, //導航欄背景顏色
actionsForegroundColor: Colors.white, //leading和trailing圖示或文字顏色
),
child: SafeArea(
top: false,
bottom: false,
child: Container(
child: Text('This is a cupertino style page', style: TextStyle(fontSize: 16, color: Colors.black),),
),
),
);
複製程式碼
CupertinoTabBar
Cupertino風格的標籤欄,通常與CupertinoTabScaffold一起使用,作為CupertinoTabScaffold的tabBar屬性值。具體使用方法如下:
final List<String> _titles = ['首頁', '產品', '更多'];
final List<Text> _pageContents = [Text('This is Home page'), Text('This is Product page'), Text('This is More page')];
int _selectedIndex = 0;
@override
Widget build(BuildContext context) {
return CupertinoTabScaffold(
tabBar: CupertinoTabBar( //作為整個頁面框架的底部標籤欄
currentIndex: _selectedIndex, //當前定位的索引
onTap: (index) { //點選標籤欄的事件監聽方法
setState(() {
_selectedIndex = index;
});
},
items: <BottomNavigationBarItem> [ //標籤欄項集合
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text(_titles[0]),
),
BottomNavigationBarItem(
icon: Icon(Icons.list),
title: Text(_titles[1]),
),
BottomNavigationBarItem(
icon: Icon(Icons.more_horiz),
title: Text(_titles[2]),
),
],
),
tabBuilder: (BuildContext context, int index) { //標籤欄對應的頁面建立
return CupertinoTabView(
builder: (BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text(_titles[index]),
),
child: Center(
child: _pageContents[index],
),
);
},
);
},
);
}
複製程式碼
CupertinoNavigationBar和CupertinoTabBar顯示效果如下圖:
總結
本篇我們對Flutter開發中常見的選擇器、彈框和標題欄、標籤欄進行了介紹,相信大家通過閱讀例子程式碼已經有了一個直觀的瞭解,後續我們將繼續介紹常用Widget之佈局Widget,敬請期待。
說明:
文章轉載自對應的“Flutter程式設計指南”微信公眾號,更多Flutter相關技術文章請關注微信公眾號獲取。