前言
相信不少同學(xué)已經(jīng)通過(guò)線上直播觀看了本周Google舉辦的Flutter Live 2018棺耍,在本次活動(dòng)中Google正式發(fā)布了Flutter 1.0版本漫玄,這對(duì)于正在學(xué)習(xí)Flutter或已經(jīng)使用Flutter進(jìn)行應(yīng)用開(kāi)發(fā)的我們都是一個(gè)好消息在旱,1.0版本中增加了一些新的特性辕羽,并且是目前最穩(wěn)定的版本惹挟,沒(méi)有了解本次活動(dòng)內(nèi)容的同學(xué)可以通過(guò)如下鏈接查看拆魏。
Flutter Live 2018舉辦后也在本周掀起了一波Flutter普及小熱潮,本公眾號(hào)將一如既往的給大家分享學(xué)習(xí)Flutter過(guò)程的心得體會(huì)雪猪、經(jīng)驗(yàn)總結(jié)和開(kāi)發(fā)實(shí)戰(zhàn)栏尚。希望給初學(xué)Flutter的同學(xué)一點(diǎn)兒幫助,同時(shí)也可以和正在使用Flutter進(jìn)行應(yīng)用開(kāi)發(fā)的同學(xué)一起交流學(xué)習(xí)浪蹂。
話不多說(shuō)抵栈,下面我們進(jìn)入本篇主題。上一篇文章給大家分享了一部分Flutter日常開(kāi)發(fā)中常用的Widget和其屬性的使用介紹坤次,其中包括文本古劲、圖片、按鈕缰猴、輸入控件和選擇控件等产艾,這些都是應(yīng)用開(kāi)發(fā)中最基本的UI展示控件,接下來(lái)我們將繼續(xù)向大家詳細(xì)介紹其他一些常用Widget滑绒。
常用Widget介紹
日期闷堡、時(shí)間選擇器和通用選擇器
選擇器對(duì)應(yīng)的Widget在Flutter中也有兩種風(fēng)格的實(shí)現(xiàn),具體用法和使用例子如下疑故。
Material design風(fēng)格的日期選擇器
showDatePicker(
context: context,
initialDate: DateTime.parse("20181209"), //初始選中日期
firstDate: DateTime.parse("20181109"), //可選日期范圍第一個(gè)日期
lastDate: DateTime.parse("20190109"), //可選日期范圍最后一個(gè)日期
selectableDayPredicate: (dateTime) { //通過(guò)此方法可以過(guò)濾掉可選范圍內(nèi)不可選的特定日期
if(dateTime.day == 10 || dateTime.day == 20 || dateTime.day == 30) {
//此處表示10號(hào)杠览、20號(hào)、30號(hào)不可選
return false;
}
return true;
},
initialDatePickerMode: DatePickerMode.day, //初始化選擇模式纵势,有day和year兩種
).then((dateTime) { //選擇日期后點(diǎn)擊OK拿到的日期結(jié)果
print('當(dāng)前選擇了:${dateTime.year}年${dateTime.month}月${dateTime.day}日');
});
顯示效果如下圖:
Material design風(fēng)格的時(shí)間選擇器
showTimePicker(
context: context,
initialTime: TimeOfDay.now(), //初始化顯示時(shí)間
).then((timeOfDay) { //選擇時(shí)間后點(diǎn)擊OK拿到的時(shí)間結(jié)果
if(timeOfDay == null) {
return;
}
print('當(dāng)前選擇了:${timeOfDay.hour}時(shí)${timeOfDay.minute}分');
});
顯示效果如下圖:
Cupertino風(fēng)格的日期選擇器CupertinoDatePicker
CupertinoDatePicker(
mode: CupertinoDatePickerMode.date, //日期時(shí)間模式踱阿,此處為日期模式
onDateTimeChanged: (dateTime) { //日期改變時(shí)調(diào)用的方法
if (dateTime == null) {
return;
}
print('當(dāng)前選擇了:${dateTime.year}年${dateTime.month}月${dateTime.day}日');
},
initialDateTime: DateTime.now(), //初始化展示時(shí)的日期時(shí)間
minimumYear: 2018, //最小年份,只有mode為date時(shí)有效
maximumYear: 2019, //最大年份钦铁,只有mode為date時(shí)有效
),
CupertinoDatePicker(
mode: CupertinoDatePickerMode.dateAndTime, //日期時(shí)間模式软舌,此處為日期和時(shí)間模式
onDateTimeChanged: (dateTime) {
if (dateTime == null) {
return;
}
print('當(dāng)前選擇了:${dateTime.year}年${dateTime.month}月${dateTime.day}日 ${dateTime.hour}時(shí)${dateTime.minute}分${dateTime.second}秒');
},
initialDateTime: DateTime.now(),
minimumDate: DateTime.parse("20181109"), //最小日期時(shí)間,只有mode為dateAndTime時(shí)有效
maximumDate: DateTime.parse("20190109"), //最大日期時(shí)間牛曹,只有mode為dateAndTime時(shí)有效
use24hFormat: false, // 是否使用24小時(shí)格式佛点,此處不使用,則選擇時(shí)可以選擇AM和PM值
),
CupertinoDatePicker(
mode: CupertinoDatePickerMode.time, //日期時(shí)間模式黎比,此處為時(shí)間模式
onDateTimeChanged: (dateTime) {
if (dateTime == null) {
return;
}
print('當(dāng)前選擇了:${dateTime.hour}時(shí)${dateTime.minute}分${dateTime.second}秒');
},
initialDateTime: DateTime.now(),
use24hFormat: true, // 是否使用24小時(shí)格式超营,此處使用
),
顯示效果如下圖:
Cupertino風(fēng)格的時(shí)間選擇器CupertinoTimerPicker
CupertinoTimerPicker(
mode: CupertinoTimerPickerMode.hms, //可以設(shè)置時(shí)分、時(shí)分秒和分秒三種模式
initialTimerDuration: Duration(hours: 1, minutes: 35, seconds: 50), // 默認(rèn)顯示的時(shí)間值
minuteInterval: 5, // 分值間隔阅虫,必須能夠被initialTimerDuration.inMinutes整除
secondInterval: 10, // 秒值間隔糟描,必須能夠被initialTimerDuration.inSeconds整除,此時(shí)設(shè)置為10书妻,則選擇項(xiàng)為0、10、20躲履、30见间、40、50六個(gè)值
onTimerDurationChanged: (duration) {
print('當(dāng)前選擇了:${duration.inHours}時(shí)${duration.inMinutes-duration.inHours*60}分${duration.inSeconds-duration.inMinutes*60}秒');
},
)
顯示效果如下圖:
Cupertino風(fēng)格的通用選擇器CupertinoPicker
CupertinoPicker(
backgroundColor: Colors.white, //選擇器背景色
itemExtent: 30, //item的高度
onSelectedItemChanged: (index) { //選中item的位置索引
print("index = $index}");
},
children: <Widget>[ //所有的選擇項(xiàng)
Text('Apple'),
Text('Banana'),
Text('Orange'),
],
)
顯示效果如下圖:
常用彈框和信息提示浮層
常見(jiàn)的彈框主要包含Material design風(fēng)格的SimpleDialog工猜、AlertDialog米诉、BottomSheet等,和Cupertino風(fēng)格的CupertinoDialog篷帅、CupertinoAlertDialog史侣、CupertinoActionSheet等。
SimppleDialog和AlertDialog
SimpleDialog和AlertDialog本身都是一個(gè)Widget魏身,使用時(shí)需要通過(guò)showDialog方法來(lái)展示惊橱。
// 展示SimpleDialog
showDialog( //展示Dialog的方法
context: context,
builder: (context) {
return SimpleDialog(
title: Text('評(píng)價(jià)一下'), //標(biāo)題
titlePadding: EdgeInsets.all(20), //標(biāo)題的padding值
children: <Widget>[ //彈框中的選項(xiàng)
SimpleDialogOption( //每一個(gè)選項(xiàng)都是一個(gè)SimpleDialogOption Widget
onPressed: (){
print('給個(gè)好評(píng)');
Navigator.pop(context);
},
child: Text('給好評(píng)'), //選項(xiàng)提示文案
),
SimpleDialogOption(
onPressed: (){
print('殘忍拒絕');
Navigator.pop(context);
},
child: Text('殘忍拒絕'),
),
SimpleDialogOption(
onPressed: (){
print('我有意見(jiàn)');
Navigator.pop(context);
},
child: Text('我有意見(jiàn)'),
),
],
contentPadding: EdgeInsets.all(0),
);
},
);
//展示AlertDialog
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('提示'), //標(biāo)題
titlePadding: EdgeInsets.all(20), //標(biāo)題的padding值
content: Text('是否想放棄學(xué)習(xí)Flutter'), //彈框展示主要內(nèi)容
contentPadding: EdgeInsets.only(left: 20, right: 20), //內(nèi)容的padding值
actions: <Widget>[ //操作按鈕數(shù)組
FlatButton(
onPressed: () {
print("取消");
Navigator.pop(context);
},
child: Text('取消'),
),
FlatButton(
onPressed: () {
print('確定');
Navigator.pop(context);
},
child: Text('確定'),
),
],
);
},
);
顯示效果如下圖:
持久性BottomSheet和模態(tài)BottomSheet
BottomSheet一般不會(huì)直接創(chuàng)建,通常是通過(guò)ScaffoldState.showBottomSheet方法來(lái)創(chuàng)建持久性BottomSheet箭昵,通過(guò)showModalBottomSheet方法來(lái)創(chuàng)建模態(tài)BottomSheet税朴。
// 創(chuàng)建持久性BottomSheet
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey, //設(shè)置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");
//通過(guò)獲取當(dāng)前ScaffoldState來(lái)展示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
)
)
)
);
});
}
),
);
}
//創(chuàng)建模態(tài)BottomSheet
Widget _buildModalBottomSheet(BuildContext context) {
return Container(
child: RaisedButton(
child: Text("ModalBottomSheet"),
onPressed: () {
print("ModalBottomSheet");
//直接使用showModalBottomSheet方法創(chuàng)建模態(tài)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已經(jīng)被標(biāo)記為過(guò)時(shí)的Widget,這里就只介紹CupertinoAlertDialog的用法家制。
showDialog( //通過(guò)showDialog方法展示alert彈框
context: context,
builder: (context) {
return CupertinoAlertDialog(
title: Text('提示'), //彈框標(biāo)題
content: Text('是否想放棄學(xué)習(xí)Flutter'), //彈框內(nèi)容
actions: <Widget>[ //操作控件
CupertinoDialogAction(
onPressed: () { //控件點(diǎn)擊監(jiān)聽(tīng)
print("我不會(huì)放棄的");
Navigator.pop(context);
},
textStyle: TextStyle(fontSize: 18, color: Colors.blueAccent), //按鈕上的文本風(fēng)格
child: Text('取消'), //控件顯示內(nèi)容
),
CupertinoDialogAction(
onPressed: () {
print("我投降");
Navigator.pop(context);
},
textStyle: TextStyle(fontSize: 18, color: Colors.grey),
child: Text('確定'),
),
],
);
},
);
顯示效果如下圖:
CupertinoActionSheet
該Widget通常作為子Widget傳遞給showCupertinoModalPopup方法正林,由該方法將其通過(guò)從屏幕底部向上滑動(dòng)來(lái)顯示。
showCupertinoModalPopup(
context: context,
builder: (context) {
return CupertinoActionSheet(
title: Text('提示', style: TextStyle(fontSize: 22),), //標(biāo)題
message: Text('麻煩抽出幾分鐘對(duì)該軟件進(jìn)行評(píng)價(jià)颤殴,謝謝!'), //提示內(nèi)容
actions: <Widget>[ //操作按鈕集合
CupertinoActionSheetAction(
onPressed: (){
Navigator.pop(context);
},
child: Text('給個(gè)好評(píng)'),
),
CupertinoActionSheetAction(
onPressed: (){
Navigator.pop(context);
},
child: Text('我要吐槽'),
),
],
cancelButton: CupertinoActionSheetAction( //取消按鈕
onPressed: () {
Navigator.pop(context);
},
child: Text('取消'),
),
);
},
);
顯示效果如下圖:
導(dǎo)航欄和標(biāo)簽欄
導(dǎo)航欄和標(biāo)簽欄是頁(yè)面框架搭建常用的控件觅廓,F(xiàn)lutter中主要包含的對(duì)應(yīng)Widget有Material design風(fēng)格的BottomNavigationBar、Tabbar和Cupertino風(fēng)格的CupertinoNavigationBar涵但、CupertinoTabBar等等杈绸。
BottomNavigationBar
該Widget通常在Material design風(fēng)格的頁(yè)面框架Widget Scaffold中使用,作為Scaffold的一個(gè)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( //應(yīng)用欄
title: Text(widget.title),
),
body: widgetOptions[selectedIndex], //頁(yè)面內(nèi)容
bottomNavigationBar: BottomNavigationBar( //底部導(dǎo)航欄
items: <BottomNavigationBarItem>[ //導(dǎo)航欄選項(xiàng)集合
BottomNavigationBarItem( //底部單個(gè)導(dǎo)航欄選項(xiàng)
icon: Icon(Icons.home), //圖標(biāo)
title: Text('首頁(yè)'), //標(biāo)題
),
BottomNavigationBarItem(
icon: Icon(Icons.list),
title: Text('產(chǎn)品'),
),
BottomNavigationBarItem(
icon: Icon(Icons.more_horiz),
title: Text('更多'),
),
],
currentIndex: selectedIndex, //當(dāng)前導(dǎo)航欄選中的索引
fixedColor: Colors.redAccent, //選中項(xiàng)的標(biāo)題顏色
onTap: (index) { //導(dǎo)航欄項(xiàng)點(diǎn)擊后的處理方法
setState(() {
selectedIndex = index;
});
},
),
);
}
Tabbar
Tabbar通常創(chuàng)建為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: '熱門', //標(biāo)題,和child不能同時(shí)存在芥永,只能設(shè)置一個(gè)
// child: Text('熱門'), //標(biāo)題篡殷,和text不能同時(shí)存在
icon: Icon(Icons.home), //標(biāo)題對(duì)應(yīng)的圖標(biāo)
),
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( //應(yīng)用欄
title: Text(widget.title),
bottom: TabBar(
controller: _controller, //TabBar控制器,通過(guò)給controller對(duì)象添加addListener方法來(lái)監(jiān)聽(tīng)切換動(dòng)作
tabs: _tabs, //標(biāo)簽欄顯示項(xiàng)集合
),
),
body: _tabViews[_selectedIndex], //頁(yè)面顯示的內(nèi)容
);
}
BottomNavigationBar和Tabbar顯示效果如下圖:
CupertinoNavigationBar
Cupertino風(fēng)格的頂部導(dǎo)航欄埋涧,通常與CupertinoPageScaffold一起使用板辽。
CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Center(child: Text('詳情', style: TextStyle(color: Colors.white),),), //導(dǎo)航欄中間控件
leading: Icon(Icons.arrow_back_ios, size: 18,), //導(dǎo)航欄左邊控件
trailing: Text('退出'), //導(dǎo)航欄右邊控件
backgroundColor: Colors.blueAccent, //導(dǎo)航欄背景顏色
actionsForegroundColor: Colors.white, //leading和trailing圖標(biāo)或文本顏色
),
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風(fēng)格的標(biāo)簽欄,通常與CupertinoTabScaffold一起使用棘催,作為CupertinoTabScaffold的tabBar屬性值劲弦。具體使用方法如下:
final List<String> _titles = ['首頁(yè)', '產(chǎn)品', '更多'];
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( //作為整個(gè)頁(yè)面框架的底部標(biāo)簽欄
currentIndex: _selectedIndex, //當(dāng)前定位的索引
onTap: (index) { //點(diǎn)擊標(biāo)簽欄的事件監(jiān)聽(tīng)方法
setState(() {
_selectedIndex = index;
});
},
items: <BottomNavigationBarItem> [ //標(biāo)簽欄項(xiàng)集合
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) { //標(biāo)簽欄對(duì)應(yīng)的頁(yè)面創(chuàng)建
return CupertinoTabView(
builder: (BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text(_titles[index]),
),
child: Center(
child: _pageContents[index],
),
);
},
);
},
);
}
CupertinoNavigationBar和CupertinoTabBar顯示效果如下圖:
總結(jié)
本篇我們對(duì)Flutter開(kāi)發(fā)中常見(jiàn)的選擇器、彈框和標(biāo)題欄醇坝、標(biāo)簽欄進(jìn)行了介紹邑跪,相信大家通過(guò)閱讀例子代碼已經(jīng)有了一個(gè)直觀的了解,后續(xù)我們將繼續(xù)介紹常用Widget之布局Widget,敬請(qǐng)期待画畅。
說(shuō)明:
文章轉(zhuǎn)載自對(duì)應(yīng)的“Flutter編程指南”微信公眾號(hào)砸琅,更多Flutter相關(guān)技術(shù)文章請(qǐng)關(guān)注微信公眾號(hào)獲取。