1.主題色主題色設(shè)置
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',//針對Android 里面可用
theme: ThemeData(
primarySwatch: Colors.yellow,//主題色設(shè)置,深色:則時間和電池顏色為白色;淺色:則時間和電池顏色為黑色
highlightColor: Color.fromRGBO(1, 0, 0, 0.0),//去掉tabBar默認選中效果
splashColor: Color.fromRGBO(1, 0, 0, 0.0),//去掉tabBar默認選中效果
),
home: RootPage(),
);
}
}
2.ListView去掉iPhoneX劉海
MediaQuery.removePadding -> removeTop: true
Container(
color: Color.fromRGBO(220, 220, 220, 1.0),
child: MediaQuery.removePadding(
removeTop: true,
context: context,
child: ListView(
children: <Widget>[
Container(
color: Colors.white,
height: 200,
),
SizedBox(height: 10,),
DiscoverCell(imageName: 'images/微信支付1.png',title: '支付',),
],
),
),
),
3.Image設(shè)置圓角
Row(
children: <Widget>[
Container(
width: 70,
height: 70,
// child: Image(image: AssetImage('images/Steven.png'),),//寫在此處設(shè)置圓角無效
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(10.0),
image: DecorationImage(image:AssetImage('images/Steven.png'),
fit: BoxFit.cover)//設(shè)置圖片的填充模式
),
),//頭像
Container(),//右邊部分
],
)
設(shè)置圓形圖片
CircleAvatar(
backgroundImage: new AssetImage('images/1.jpeg'),
radius: 100.0,
)
4.設(shè)備的寬高獲取
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
5.文字居中方向設(shè)置
//Container屬性
alignment: Alignment.centerLeft,
6.網(wǎng)絡圖片和本地圖片的加載
Container(
width: 34,
height: 34,
margin: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.0),
image: DecorationImage(
image: imageUrl != null
? NetworkImage(imageUrl) //網(wǎng)絡圖片
: AssetImage(imageAssets),//本地圖片
)),
)
7.鏈式編程-添加數(shù)據(jù)
@override
//數(shù)據(jù)、對象創(chuàng)建
void initState() {
super.initState();
//鏈式編程,調(diào)用兩次addAllData并返回數(shù)組到 _listDatas
_listDatas..addAll(datas)..addAll(datas);
//數(shù)據(jù)排序
_listDatas.sort((Friends a, Friends b){
return a.indexLetter.compareTo(b.indexLetter);
});
//print('_listDatas:$_listDatas');
}
8.相除取整
~/
onVerticalDragUpdate: (DragUpdateDetails details){
print(details.globalPosition.dy);//相對于整個屏幕的值
RenderBox box = context.findRenderObject();
//計算當前位置 坐標轉(zhuǎn)換, 算出y值
double y = box.globalToLocal(details.globalPosition).dy;
//y值除以每個item的高度就是當前的索引
//每一個item的高度
var itemH = ScreenHeight(context)/2/INDEX_WORDS.length;
int index = y ~/ itemH;//相除取整
print(box.globalToLocal(details.globalPosition));
},
9.數(shù)組越界處理
//使用clamp
//取值范圍0~INDEX_WORDS.length-1 添加安全判斷
int index = (y ~/ itemHeight).clamp(0, INDEX_WORDS.length - 1);
10.定義回調(diào)函數(shù)和調(diào)用
//定義回調(diào)函數(shù)
final void Function(String str) indexBarCallBack;
//構(gòu)造方法
const IndexBar({Key key, this.indexBarCallBack}) : super(key: key);
//調(diào)用該callBack
//監(jiān)聽所在位置:計算當前位置
onVerticalDragUpdate: (DragUpdateDetails details){
widget.indexBarCallBack(getIndex(context, details.globalPosition));
},
//外部使用
IndexBar(
indexBarCallBack: (String str){
print("收到了:$str");
},
),
11.PopupMenuButton 使用
Container(
margin: EdgeInsets.only(right: 10),
child: PopupMenuButton(
offset: Offset(0, 60.0),
child: Image(image: AssetImage('images/圓加.png'),width: 25,),
itemBuilder: _buildPopupMenuItem,
),
)
//創(chuàng)建Item的方法!
PopupMenuItem<String> _buildItem(String imgAss, String title) {
return PopupMenuItem(
child: Row(
children: <Widget>[
Image(
image: AssetImage(imgAss),
width: 20,
),
Container(
width: 20,
),
Text(
title,
style: TextStyle(color: Colors.white),
),
],
),
);
}
//回調(diào)方法
List<PopupMenuItem<String>> _buildPopupMenuItem(BuildContext context) {
return <PopupMenuItem<String>>[
_buildItem('images/發(fā)起群聊.png', '發(fā)起群聊'),
_buildItem('images/添加朋友.png', '添加朋友'),
_buildItem('images/掃一掃1.png', '掃一掃'),
_buildItem('images/收付款.png', '收付款'),
];
}
設(shè)置popup背景顏色
//MaterialApp -> theme -> cardColor
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',//針對Android 里面可用
theme: ThemeData(
primarySwatch: Colors.yellow,//主題色設(shè)置,深色:則時間和電池顏色為白色;淺色:則時間和電池顏色為黑色
highlightColor: Color.fromRGBO(1, 0, 0, 0.0),//去掉tabBar默認選中效果
splashColor: Color.fromRGBO(1, 0, 0, 0.0),//去掉tabBar默認選中效果
cardColor: Color.fromRGBO(1, 1, 1, 0.65),//設(shè)置popup背景顏色
),
home: RootPage(),
)
效果圖:

12.滑動ListView讓鍵盤消失
FocusScope.of(context).requestFocus(FocusNode());
//監(jiān)聽ListView的滑動事件,讓鍵盤消失
Expanded(
flex: 1, //占據(jù)剩余空間
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: NotificationListener(
onNotification: (ScrollNotification note){
FocusScope.of(context).requestFocus(FocusNode());
},//滑動讓鍵盤消失
child: ListView.builder(
itemCount: _models.length,
itemBuilder: _itemForRow,
),
),
),
)
13.Containter 設(shè)置部分圓角和陰影效果
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: 10, bottom: 10),
decoration: BoxDecoration(
color: Colors.white,
// 設(shè)置陰影 要在裁剪之外添加一個Containter里面處理,否則無效
boxShadow: [
BoxShadow(
color: Color(0xff333333).withOpacity(0.05),
offset: Offset(0, 1.0),
blurRadius: 5),
],
),
child: new ClipRRect(
// 設(shè)置局部圓角
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(5),
bottomRight: Radius.circular(5),
),
child: Container(
height: ScreenUtil().setHeight(147),
child: Container(
margin: EdgeInsets.only(left: 40, right: 40),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: navigatorList.map((item) {
return _navigatorItem(context, item);
}).toList(),
),
),
),
),
);
}
14. Scaffold 的 appBar 去掉底部陰影
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
centerTitle: true,
title: Text(
"發(fā)現(xiàn)",
style: TextStyle(
color: Color(0xff333333), fontSize: ScreenUtil().setSp(34)),
),
bottomOpacity: 0,
elevation: 0, // 去掉底部陰影
),
);
其他
@override
Widget build(BuildContext context) {
return Scaffold(
//頭部元素 比如:左側(cè)返回按鈕 中間標題 右側(cè)菜單
appBar: AppBar(
title: Text('Scaffold腳手架組件示例'),
),
//視圖內(nèi)容部分 通常作為應用頁面的主顯示區(qū)域
body: Center(
child: Text('Scaffold'),
),
//底部導航欄
bottomNavigationBar: BottomAppBar(
child: Container(height: 50.0,),
),
//添加FAB按鈕
floatingActionButton: FloatingActionButton(
onPressed: () {},
tooltip: '增加',
child: Icon(Icons.add),
),
//FAB按鈕居中展示
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
15.Image圖片設(shè)置寬度自適應
Container(
margin: EdgeInsets.only(left: 15, right: 15),
height: ScreenUtil().setHeight(243),
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'http://fdfs.xmcdn.com/group63/M0A/99/95/wKgMaFz_RD-BDyFjAAIO0iRtj0U176.jpg'),
fit: BoxFit.fitWidth,
alignment: Alignment.topCenter,
)),
),
16.FlutterListView嵌套GridView滾動沖突問題
ListView和GirdView都是滾動Widget 兩個部件嵌套就會存在滾動沖突,解決辦法如下
body: new ListView(
shrinkWrap: true,
padding: EdgeInsets.all(0),
children: <Widget>[
new GridView.count(
padding: EdgeInsets.all(0),
physics: new NeverScrollableScrollPhysics(),//增加
shrinkWrap: true,//增加
crossAxisCount: 3,
children:<Widget>[]
],
),
① 處理listview嵌套報錯
shrinkWrap: true,
②處理GridView中滑動父級Listview無法滑動
physics: new NeverScrollableScrollPhysics();
17.Flutter 自定義TabBar和修改indiactor 寬度
1. 關(guān)鍵代碼
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class FriendsList extends StatefulWidget {
@override
_FriendsListState createState() => _FriendsListState();
}
class _FriendsListState extends State<FriendsList>
with SingleTickerProviderStateMixin {
TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(initialIndex: 0, length: 2, vsync: this);
}
@override
void dispose() {
super.dispose();
_tabController.dispose();
}
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: Container(
height: ScreenUtil().setHeight(73),
alignment: Alignment.topLeft,
child: TabBar(
tabs: [
Tab(text: '好友'),
Tab(text: '心動'),
],
controller: _tabController,
indicatorWeight: 2,
indicatorPadding: EdgeInsets.only(left: 10, right: 10),
labelPadding: EdgeInsets.symmetric(horizontal: 10),
isScrollable: true,
indicatorColor: Color(0xffFF7E98),
labelColor: Color(0xffFF7E98),
labelStyle: TextStyle(
fontSize: ScreenUtil().setSp(36),
color: Color(0xffFF7E98),
fontWeight: FontWeight.w500,
),
unselectedLabelColor: Color(0xffAAAAAA),
unselectedLabelStyle: TextStyle(
fontSize: ScreenUtil().setSp(32), color: Color(0xffAAAAAA)),
indicatorSize: TabBarIndicatorSize.label,
)),
backgroundColor: Colors.white,
elevation: 0,
),
body: TabBarView(
children: [
Container(
child: Center(
child: Text("好友頁面"),
),
),
Container(
child: Center(
child: Text("心動頁面"),
),
),
],
controller: _tabController,
),
),
);
}
}
2. 效果圖

18 fluro 插件 實現(xiàn)appBar不要出現(xiàn)返回鍵
Application.router.navigateTo(context, "/index",replace: true);
19.文字溢出處理
①Expanded + TextOverflow.ellipsis 設(shè)置省略號
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("LayoutPage")),
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.star,
size: 16.0,
color: Colors.grey,
),
Padding(padding: new EdgeInsets.only(left: 5.0)),
Expanded(
child: Text(
"100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000",
style: new TextStyle(color: Colors.grey, fontSize: 14.0),
// 設(shè)置省略號
overflow: TextOverflow.ellipsis,
// 設(shè)置最大行數(shù)
maxLines: 1,
),
)
],
),
),
);
}
② Expanded + TextOverflow.ellipsis 不生效
通過
- 限定Container 寬度
- Row 布局嵌套 Expanded 可以添加約束

20.數(shù)據(jù)解析報錯之關(guān)鍵字 do
do 為關(guān)鍵字,不能設(shè)置為Model的屬性,應該用其他名稱替換
class UserChatList {
int doType;
UserChatList({this.doType});
UserChatList.fromJson(Map<String, dynamic> json) {
doType = json['do'];
}
21.聊天消息UI搭建
效果圖

思路
- ①Positison 設(shè)置
right: ScreenUtil().setWidth(20),
bottom: -ScreenUtil().setHeight(50),
- ② Stack 設(shè)置溢出顯示
overflow: Overflow.visible
關(guān)鍵代碼
/// 聊天Widget
Widget ChatWidget(String chatType, String msg) {
// 1 發(fā)出者
if (chatType == 'send') {
return Container(
decoration: BoxDecoration(
color: Colors.white,
// 設(shè)置陰影
boxShadow: [
BoxShadow(
color: Color(0xffFF7E98),
offset: Offset(0, 1),
blurRadius: 8,
)
],
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15),
topRight: Radius.circular(15),
bottomRight: Radius.circular(15)),
),
height: ScreenUtil().setHeight(80),
margin: EdgeInsets.only(
top: ScreenUtil().setHeight(40),
),
padding: EdgeInsets.only(
left: ScreenUtil().setWidth(40),
right: ScreenUtil().setWidth(40),
top: ScreenUtil().setHeight(10),
bottom: ScreenUtil().setHeight(10)),
child: Text(
msg != null && msg.length > 0 ? msg : '',
style: TextStyle(
fontSize: ScreenUtil().setSp(30), color: Color(0xff333333)),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
);
} else if (chatType == 'minisend') {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Stack(
overflow: Overflow.visible,
children: <Widget>[
// 消息
Container(
decoration: BoxDecoration(
color: Colors.white,
// 設(shè)置陰影
boxShadow: [
BoxShadow(
color: Color(0xffFF7E98),
offset: Offset(1, 1),
blurRadius: 8,
)
],
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15),
topRight: Radius.circular(15),
bottomRight: Radius.circular(15)),
),
height: ScreenUtil().setHeight(80),
margin: EdgeInsets.only(
top: ScreenUtil().setHeight(40),
),
padding: EdgeInsets.only(
left: ScreenUtil().setWidth(40),
right: ScreenUtil().setWidth(40),
top: ScreenUtil().setHeight(10),
bottom: ScreenUtil().setHeight(10)),
child: Text(
'??很想認識你??',
style: TextStyle(
fontSize: ScreenUtil().setSp(30),
color: Color(0xff333333)),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
Positioned(
right: ScreenUtil().setWidth(20),
bottom: -ScreenUtil().setHeight(50),
child: // 小程序路徑
Container(
margin: EdgeInsets.only(top: ScreenUtil().setHeight(16)),
child: Row(
children: <Widget>[
Text(
'去小程序查看',
style: TextStyle(
fontSize: ScreenUtil().setSp(22),
color: Color(0xffFF7E98)),
),
Icon(
MyIcons.sex_boy,
size: ScreenUtil().setSp(16),
color: Color(0xffFF7E98),
)
],
),
),
),
],
),
],
);
} else if (chatType == 'mine') {
return Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Colors.white,
// 設(shè)置陰影
boxShadow: [
BoxShadow(
color: Color(0xffFF7E98),
offset: Offset(0, 1),
blurRadius: 8,
)
],
// 設(shè)置漸變色
gradient: LinearGradient(
colors: [Color(0xFFFF7E98), Color(0xFFFD7BAB)],
begin: Alignment(-1, -1),
end: Alignment(1.0, 0.56),
),
// 設(shè)置圓角
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15),
topRight: Radius.circular(15),
bottomLeft: Radius.circular(15)),
),
height: ScreenUtil().setHeight(80),
margin: EdgeInsets.only(
top: ScreenUtil().setHeight(40),
),
padding: EdgeInsets.only(
left: ScreenUtil().setWidth(40),
right: ScreenUtil().setWidth(40),
top: ScreenUtil().setHeight(10),
bottom: ScreenUtil().setHeight(10)),
child: Text(
msg != null && msg.length > 0 ? msg : '',
style: TextStyle(
fontSize: ScreenUtil().setSp(30), color: Colors.white),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
)
],
);
} else {
return Container(
margin: EdgeInsets.only(bottom:ScreenUtil().setHeight(40) ),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Stack(
overflow: Overflow.visible,
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Colors.white,
// 設(shè)置陰影
boxShadow: [
BoxShadow(
color: Color(0xffFF7E98),
offset: Offset(0, 1),
blurRadius: 8,
)
],
// 設(shè)置漸變色
gradient: LinearGradient(
colors: [Color(0xFFFF7E98), Color(0xFFFD7BAB)],
begin: Alignment(-1, -1),
end: Alignment(1.0, 0.56),
),
// 設(shè)置圓角
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15),
topRight: Radius.circular(15),
bottomLeft: Radius.circular(15)),
),
height: ScreenUtil().setHeight(80),
margin: EdgeInsets.only(
top: ScreenUtil().setHeight(40),
),
padding: EdgeInsets.only(
left: ScreenUtil().setWidth(40),
right: ScreenUtil().setWidth(40),
top: ScreenUtil().setHeight(10),
bottom: ScreenUtil().setHeight(10)),
child: Text(
msg != null && msg.length > 0 ? msg : '',
style: TextStyle(
fontSize: ScreenUtil().setSp(30), color: Colors.white),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
// 小程序路徑
Positioned(
left: ScreenUtil().setWidth(20),
bottom: -ScreenUtil().setHeight(50),
child: Container(
margin: EdgeInsets.only(top: ScreenUtil().setHeight(16),),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text(
'去小程序查看',
style: TextStyle(
fontSize: ScreenUtil().setSp(22),
color: Color(0xffFF7E98)),
),
Icon(
MyIcons.sex_boy,
size: ScreenUtil().setSp(16),
color: Color(0xffFF7E98),
)
],
),
),
),
],
)
],
),
);
}
}
22. Flutter 復制到剪切板
通過Clipboard實現(xiàn)復制操作
1.聲明key并在Scaffold指定key
/// 剪切板Key
final clicpBoardKey = new GlobalKey<ScaffoldState>();
return Scaffold(
key: clicpBoardKey,
);
2.實現(xiàn)復制操作并彈出SnackBar
Clipboard.setData(ClipboardData(text: '人生若只初相見'));
clicpBoardKey.currentState.showSnackBar(SnackBar(content: Text('已復制到剪貼板')));
其他
Scaffold.of(context).showSnackBar(SnackBar(
//提示信息內(nèi)容部分
content: Text("顯示SnackBar"),
));
23.Url 轉(zhuǎn)義 decode
decodeURIComponent('%2Fpage%2Forigin%2Forigin%3Fuid%3D')
24.獲取widget 控件的尺寸
- 通過Context
- 通過GlobalKey
- 通過LayoutChangedNotification(重寫)
// 寬度
width: MediaQuery.of(context).size.width,
// 高度
height: MediaQuery.of(context).size.height * 0.05,
// 注意: context 為父組件的context
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class NewSizeChangedLayoutNotification extends LayoutChangedNotification{
Size size;
NewSizeChangedLayoutNotification(this.size);
}
class NewSizeChangedLayoutNotifier extends SingleChildRenderObjectWidget {
const NewSizeChangedLayoutNotifier({
Key key,
Widget child,
}) : super(key: key, child: child);
@override
_NewRenderSizeChangedWithCallback createRenderObject(BuildContext context) {
return _NewRenderSizeChangedWithCallback(
onLayoutChangedCallback: (Size size) {
NewSizeChangedLayoutNotification(size).dispatch(context);
}
);
}
}
typedef VoidCallbackWithParam = Function(Size size);
class _NewRenderSizeChangedWithCallback extends RenderProxyBox {
_NewRenderSizeChangedWithCallback({
RenderBox child,
@required this.onLayoutChangedCallback,
}) : assert(onLayoutChangedCallback != null),
super(child);
final VoidCallbackWithParam onLayoutChangedCallback;
Size _oldSize;
@override
void performLayout() {
super.performLayout();
//在第一次layout結(jié)束后就會進行通知
if (size != _oldSize)
onLayoutChangedCallback(size);
_oldSize = size;
}
}
25.decoration相關(guān)
1) 邊框
// 同時設(shè)置4條邊框:1px粗細的黑色實線邊框
BoxDecoration(
border: Border.all(color: Colors.black, width: 1, style: BorderStyle.solid)
)
// 設(shè)置單邊框:上邊框為1px粗細的黑色實線邊框,右邊框為1px粗細的紅色實線邊框
BoxDecoration(
border: Border(
top: BorderSide(color: Colors.black, width: 1, style: BorderStyle.solid),
right: BorderSide(color: Colors.red, width: 1, style: BorderStyle.solid),
),
)
2) 圓角
// 同時設(shè)置4個角的圓角為5
BoxDecoration(
borderRadius: BorderRadius.circular(5),
)
// 設(shè)置單圓角:左上角的圓角為5,右上角的圓角為10
BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(5),
topRight: Radius.circular(10),
),
)
3) 陰影
BoxDecoration(
boxShadow: [
BoxShadow(
offset: Offset(0, 0),
blurRadius: 6,
spreadRadius: 10,
color: Color.fromARGB(20, 0, 0, 0),
),
],
)
4) 漸變色
// 從左到右,紅色到藍色的線性漸變
BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [Colors.red, Colors.blue],
),
)
// 從中心向四周擴散,紅色到藍色的徑向漸變
BoxDecoration(
gradient: RadialGradient(
center: Alignment.center,
colors: [Colors.red, Colors.blue],
),
)
// 設(shè)置角度
final gradient = Utils.parseAngleToAlignment(90);
BoxDecoration(
gradient: LinearGradient(
colors: [
Color(0xFFFFA3AD),
Color(0xFFFC5E72)
],
begin: Alignment(gradient['beginX'], gradient['beginY']),
end: Alignment(gradient['endX'], gradient['endY'])
),
borderRadius: BorderRadius.circular(2)
)
26.MaterialApp 使用講解
字段 類型
home(主頁) Widget
routes(路由) Map<String, WidgetBuilder>
theme(主題) ThemeData
debugShowMaterialGrid(調(diào)試顯示材質(zhì)網(wǎng)格) bool
navigatorKey(導航鍵) GlobalKey<NavigatorState>
onGenerateRoute(生成路由) RouteFactory
onUnknownRoute(未知路由) RouteFactory
navigatorObservers(導航觀察器) List<NavigatorObserver>
initialRoute(初始路由) String
builder(建造者) TransitionBuilder
title(標題) String
onGenerateTitle(生成標題) GenerateAppTitle
color(顏色) Color
locale(地點) Locale
localizationsDelegates(本地化委托) Iterable<LocalizationsDelegate<dynamic>>
localeResolutionCallback(區(qū)域分辨回調(diào)) LocaleResolutionCallback
supportedLocales(支持區(qū)域) Iterable<Locale>
showPerformanceOverlay(顯示性能疊加) bool
checkerboardRasterCacheImages(棋盤格光柵緩存圖像) bool
checkerboardOffscreenLayers(棋盤格層) bool
showSemanticsDebugger(顯示語義調(diào)試器) bool
debugShowCheckedModeBanner(調(diào)試顯示檢查模式橫幅) bool
27.使用FutureBuilder每調(diào)用一次setState就會重新請求future
解決方法:將 future提取出來,作為一個變量
Future<int> future;
@override
void initState() {
super.initState();
future=getInt();
}
FutureBuilder<int>(
future: future,
builder: (context, snapshot) {
return ...;
}
),
Future<int> getInt(){
return Future.value(1);
}
28.輸入框內(nèi)容為空時,長按不顯示粘貼工具欄
將輸入框中的autoFocus屬性為ture去掉
29.Flutter 左上角返回按鈕回調(diào)(CallBack)
1.1 async await 實現(xiàn)
/// 跳轉(zhuǎn)到下級頁面時 await Navigator.pushNamed
onTap: () async {
await Navigator.pushNamed(context, '/account');
//執(zhí)行 刷新數(shù)據(jù)操作
refrshData();
},
2.嵌套封裝 會導致await 失效
class NavigatorUtil{
/// 通用跳轉(zhuǎn)
static push(BuildContext context,Widget widget ) {
Navigator.push(context, PageRouteBuilder(transitionDuration: Duration(milliseconds: 300),
pageBuilder: (context, animation, secondaryAnimation){
return new FadeTransition( //使用漸隱漸入過渡,
opacity: animation,
child:widget,
);
})
);
}
}
//使用導致await失效
onTap: () async {
// 其他
await NavigatorUtil.push(context, widget);
//執(zhí)行刷新操作
},
解決方案
封裝層嵌套 async await
class NavigatorUtil{
/// 通用跳轉(zhuǎn)
static push(BuildContext context,Widget widget ) async {
await Navigator.push(context, PageRouteBuilder(transitionDuration: Duration(milliseconds: 300),
pageBuilder: (context, animation, secondaryAnimation){
return new FadeTransition( //使用漸隱漸入過渡,
opacity: animation,
child:widget,
);
})
);
}
}
30.GestureDetector 手勢沖突
解決手勢沖突 - IgnorePointer
IgnorePointer(
child: GestureDetector(
child: Container(
height: ScreenUtil().setHeight(300),
width: Screen.width,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(ScreenUtil().setWidth(20)),
topRight: Radius.circular(ScreenUtil().setWidth(20)),
),
gradient: LinearGradient(
colors: [
Color(0xFFFFFFFF),
Colors.white.withOpacity(.2),
Colors.white.withOpacity(0),
Colors.white.withOpacity(0),
Colors.white.withOpacity(0)
],
begin: Alignment(
topGradient['beginX'], topGradient['beginY']),
end: Alignment(topGradient['endX'], topGradient['endY']),
),
),
),
onTap: () {
backToTop();
},
),
),
31.TextField 設(shè)置border 顏色(黑線修改顏色)
/// 輸入框
Container(
child: Theme(
data: ThemeData(
primaryColor: Colors.white, hintColor: Colors.white),
child: TextField(
style: TextStyle(
fontSize: ScreenUtil().setSp(36),
color: Colors.white,
),
controller: inputController,
onChanged: handlePhoneInput,
autofocus: true,
decoration: new InputDecoration(
border: const UnderlineInputBorder(
borderSide: BorderSide(style: BorderStyle.solid,color: Colors.white,),
),
contentPadding: EdgeInsets.only(
left: ScreenUtil().setWidth(100),
right: ScreenUtil().setWidth(20),
top: ScreenUtil().setWidth(20),
bottom: ScreenUtil().setWidth(20),
),
hintText: '輸入手機號',
hintStyle: TextStyle(
color: Color.fromRGBO(255, 255, 255, .7),
fontSize: ScreenUtil().setSp(36),
),
),
),
),
),
32.decoration 陰影設(shè)置無邊界
通過Opacity 以及 LinearGradient設(shè)置 stops節(jié)點和colors 結(jié)合
// 頂部陰影
Opacity(
opacity: 0.23,
child: Container(
height: ScreenUtil().setHeight(129),
decoration: BoxDecoration(
gradient: LinearGradient(
stops: [
0,
.8
],
colors: [
Color(0xff565656),
Color(0xFF030303).withOpacity(0),
],
begin:
Alignment(gradient['beginX'], gradient['beginY']),
end: Alignment(gradient['endX'], gradient['endY'])),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.0),
topRight: Radius.circular(10.0),
),
),
child: Container(
margin: EdgeInsets.only(
left: ScreenUtil().setWidth(10),
right: ScreenUtil().setWidth(17),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: EdgeInsets.only(
top: ScreenUtil().setHeight(17)),
child: Row(
children: <Widget>[
Icon(
MyIcons.heart,
size: ScreenUtil().setSp(40),
color: Colors.white,
),
Container(
margin: EdgeInsets.only(
left: ScreenUtil().setWidth(5),
top: ScreenUtil().setWidth(5),
),
child: Text(
this.widget.item != null &&
this.widget.item.praises != null
? this.widget.item.praises.toString()
: '',
style: TextStyle(
fontSize: ScreenUtil().setSp(20),
color: Colors.white,
),
textAlign: TextAlign.center,
),
)
],
),
),
],
),
),
),
)
33.Dart List.asMap() 獲取下標
this.list.asMap().keys.map((i) {
// i 為下標
return _itemUI(context, i);
}).toList()
34.indexWhere 獲取數(shù)組索引
int currentIndex = this.renderList.indexWhere((item) => item.id == feed.id);
35.build runner 插件使用
build runner 插件編譯生成屬性快捷鍵
flutter packages run build_runner build --delete-conflicting-outputs
36.Container點擊區(qū)域過小
GestureDetector 內(nèi)Container不設(shè)置color點擊區(qū)域會根據(jù)內(nèi)容大小來定
37.xcrun instruments 打開模擬器
xcrun instruments -w "iPhone 8 Plus (13.1)"
39. GestureDetector處理手勢操作 behavior 行為
HitTestBehavior.opaque自己處理事件HitTestBehavior.deferToChildchild處理事件HitTestBehavior.translucent自己和child都可以接收事件
40.Widget無法居中,對齊
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: ScreenUtil().setHeight(114),
height: ScreenUtil().setHeight(114),
margin: EdgeInsets.only(
left: ScreenUtil().setWidth(10),
),
child: Center(child: FailedDot(),),
)
: Container()
],
),
41.Flutter Container 點擊區(qū)域太小
使用GestureDetector包裹Container,發(fā)現(xiàn)在Container內(nèi)容為空的區(qū)域點擊時,捕捉不到onTap點擊事件。
解決方案:在GestureDetector里面添加屬性:behavior: HitTestBehavior.opaque,即可:
GestureDetector(
behavior: HitTestBehavior.opaque,
child: Container( width: ScreenUtil().setHeight(114),
height: ScreenUtil().setHeight(114),child:Text('點我')),
onTap: () {
this.handlePlayVoice();
},
)
42.監(jiān)聽頁面返回事件(返回按鈕點擊+側(cè)滑返回)
側(cè)滑不會觸發(fā)onBack回調(diào),因此使用WillPopScope的onWillPop來實現(xiàn)
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
// 設(shè)置草稿箱
this.setCraft();
return true;
},
child: Container()
}
43PageView使用注意事項
問題描述:第一次指定加載第二個page,切換時需要切換兩次才顯示正常
原因分析:
PageView未初始化時默認index = 0,你強行修改時會導致兩個index不一致
解決辦法:
_controller = PageController(initialPage: currentIndex);
/// 切換
_controller.animateToPage(
currentIndex,
duration: Duration(
milliseconds:
(pageSwitchAnimatedTime + 100),
),
curve: Curves.ease,
);
44 ClipOval組件詳解
- 圓形裁剪(超出部分隱藏,相當于Stack的overFlow為clip)
Center(
child: ClipOval(
child: Image.asset(
"images/app.png",
width: 100.0,
height: 100.0,
fit: BoxFit.cover,
),
),
)
45如何判斷設(shè)備是否為iPad
// 1.導入設(shè)備信息插件
# 設(shè)備信息
device_info: ^0.4.0
// 2. 使用
Future<bool> isIpad() async{
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
IosDeviceInfo info = await deviceInfo.iosInfo;
if (info.name.toLowerCase().contains("ipad")) {
return true;
}
return false;
}
46 setState導致的內(nèi)存泄漏——setState() called after dispose()
錯誤原因
- 定時器沒有被銷毀(dispose 銷毀cancel)
解決方法
臨時方案
- 異步消息未返回,所以在
setState方法之前調(diào)用mouted屬性進行判斷即可
if (mounted) {
setState(() {
//refreshData
});
}
最終解決方案
@override
void dispose() {
_countdownTimer?.cancel();
super.dispose();
}
47.Flutter 設(shè)置圓角圖片
通過 ClipRRect + borderRadius 實現(xiàn)
Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
this.matchedUser.user.avatar,
fit: BoxFit.cover,
),
),
width: AdaptationUtils.px(140),
height: AdaptationUtils.px(140),
)
48.clamp 語法
顧名思義,夾緊,所得的結(jié)果不會超出這個范圍,類似于閉區(qū)間[]
例如:
int origen = 10;
int result = origen.clamp(2, 11);
print(result);//MARK:結(jié)果為10
//////////////////////////////////
int origen = 10;
int result = origen.clamp(2, 9);
print(result);//MARK:結(jié)果為9
49.Flutter 擴大點擊區(qū)域(Container)
效果圖

代碼封裝
/// 擴大點擊區(qū)域(Container)
///
/// created by hujintao
/// created at 2020-03-19
//
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class EnlargeWrapper extends StatefulWidget {
Widget child;
EdgeInsetsGeometry enlarge;
EnlargeWrapper({
this.child,
this.enlarge,
});
@override
_EnlargeWrapperState createState() => _EnlargeWrapperState();
}
class _EnlargeWrapperState extends State<EnlargeWrapper> {
@override
Widget build(BuildContext context) {
return Container(
child: this.widget.child,
padding: this.widget.enlarge ??
EdgeInsets.fromLTRB(
ScreenUtil().setWidth(40),
ScreenUtil().setWidth(40),
ScreenUtil().setWidth(40),
ScreenUtil().setWidth(40),
),
// color: Colors.yellow,//測試
color: Colors.transparent,
);
}
}
使用
Center(
child: GestureDetector(
child: EnlargeWrapper(
child: Container(
width: 100,
height: 100,
color: Colors.red,
child: Center(
child: Text('點我s撒'),
),
),
enlarge: EdgeInsets.all(50),
),
onTap: () {
Toast.show('點擊了');
},
),
)
50.根據(jù)名稱讀取文件
//根據(jù)名稱讀取文件
import 'dart:io';
readFile(name) async {
//創(chuàng)建文件對象
var file = File(name);
try {
//判斷是否存在
bool exists = await file.exists();
if (exists) {
//如果存在
print(await file.length()); //文件大小(字節(jié))---137
print(await file.lastModified()); //最后修改時間---2018-12-21 13:49:35.000
print(file.parent.path); //獲取父文件夾的路徑---C:\Users\Administrator\Desktop\dart
return await file.readAsString(); //讀取文件并返回
} else {
await file.create(recursive: true); //不存在則創(chuàng)建文件
return "未發(fā)現(xiàn)文件,已為您創(chuàng)建!Dart機器人:2333";
}
} catch (e) {
//異常處理
print(e);
}
}
使用
var result = await readFile("\Users\XXX\Desktop\dart\test.txt");
print(result);
添加所有SD卡文件名稱
// 添加所有SD卡文件名稱
localPath() {
try {
var perm =
SimplePermissions.requestPermission(Permission.ReadExternalStorage);
var sdPath = getExternalStorageDirectory();
sdPath.then((file) {
perm.then((v) {
file.list().forEach((i) {
_files.add(i.path);
});
setState(() {});
});
});
} catch (err) {
print(err);
}
}
51 Flutter 微信分享和支付回調(diào)
通過 fluwx 微信SDK插件
下載插件
# 微信sdk
fluwx: ^1.2.1+1
1.微信分享回調(diào)
import 'package:fluwx/fluwx.dart' as fluwx;
/// 微信分享監(jiān)聽
StreamSubscription wxShareListener;
@override
void initState() {
super.initState();
this.track();
initWxShareListener();
}
/// 初始化微信分享監(jiān)聽
void initWxShareListener() {
wxShareListener =
fluwx.responseFromShare.listen(this.onWxShareResponse);
}
/// 微信分享響應
void onWxShareResponse(fluwx.WeChatShareResponse response) {
print(
'pay success: ${response.errStr}, ${response.type}, ${response.errCode}, ${response.androidOpenId}');
if (response.errCode == 0) {
Toast.show('分享回來了額~~~~');
}
}
// 銷毀監(jiān)聽
@override
void dispose() {
wxShareListener.cancel();
super.dispose();
}
2.微信支付回調(diào)
import 'package:fluwx/fluwx.dart' as fluwx;
/// 微信支付監(jiān)聽
StreamSubscription fluwxPaymentListener;
@override
void initState() {
super.initState();
this.track();
initWxPayListener();
}
/// 初始化微信支付監(jiān)聽
void initWxPayListener() {
fluwxPaymentListener =
fluwx.responseFromPayment.listen(this.onWxPayResponse);
}
/// 微信支付響應
void onWxPayResponse(fluwx.WeChatPaymentResponse response) {
print(
'pay success: ${response.errStr}, ${response.type}, ${response.errCode}, ${response.androidOpenId}');
// 微信響應之后, 不允許關(guān)閉窗口
if (this.canClose) {
this.canClose = false;
setState(() {});
}
if (response.errCode == 0) {
this.checkOrderStatus();
} else {
if (response.errCode == -1) {
this.onError(PayErrorEnum.WxPayError);
} else if (response.errCode == -2) {
this.onError(PayErrorEnum.WxPayCanceled);
} else {
this.onError(PayErrorEnum.WxPayUnKnowError);
}
}
}
// 銷毀監(jiān)聽
@override
void dispose() {
fluwxPaymentListener.cancel();
super.dispose();
}
52.數(shù)據(jù)庫操作抽象類(接口封裝)
//數(shù)據(jù)庫操作抽象類
abstract class DateBaseOperate {
void insert(); //定義插入的方法
void delete(); //定義刪除的方法
void update(); //定義更新的方法
void query(); //定義一個查詢的方法
}
//數(shù)據(jù)庫操作實現(xiàn)類
class DateBaseOperateImpl extends DateBaseOperate {
//實現(xiàn)了插入的方法
void insert(){
print('實現(xiàn)了插入的方法');
}
//實現(xiàn)了刪除的方法
void delete(){
print('實現(xiàn)了刪除的方法');
}
//實現(xiàn)了更新的方法
void update(){
print('實現(xiàn)了更新的方法');
}
//實現(xiàn)了一個查詢的方法
void query(){
print('實現(xiàn)了一個查詢的方法');
}
}
main() {
var db = new DateBaseOperateImpl();
db.insert();
db.delete();
db.update();
db.query();
}
53 .繼承
//動物類
class Animal {
//動物會吃
void eat(){
print('動物會吃');
}
//動物會跑
void run(){
print('動物會跑');
}
}
//人類
class Human extends Animal {
//人類會說
void say(){
print('人類會說');
}
//人類會學習
void study(){
print('人類會學習');
}
}
main() {
print('實例化一個動物類');
var animal = new Animal();
animal.eat();
animal.run();
print('實例化一個人類');
var human = new Human();
human.eat();
human.run();
human.say();
human.study();
}
54.流程控制語句
void test(){
//if else 示例
// String today = 'Monday';
// if (today == 'Monday') {
// print('今天是星期一');
// } else if (today == 'Tuesday') {
// print('今天是星期二');
// } else {
// print('今天是個好日子');
// }
//for循環(huán)示例
var message = new StringBuffer("Hello Dart");
for (var i = 0; i < 5; i++) {
message.write('!');
}
print(message);
//forEach示例
// var arr = [0, 1, 2, 3, 4, 5, 6];
// for (var v in arr) {
// print(v);
// }
//while循環(huán)示例
// var _temp = 0;
// while(_temp < 5){
//
// print("這是一個循環(huán): " + (_temp).toString());
// _temp ++;
// }
//do-while循環(huán)示例
// var _temp = 0;
//
// do{
// print("這是一個循環(huán): " + (_temp).toString());
// _temp ++;
// }
// while(_temp < 5);
//break continue示例
var arr = [0, 1, 2, 3, 4, 5, 6];
for (var v in arr) {
if(v == 2 ){
//break;
continue;
}
print(v);
}
//switch case示例
String today = 'Monday';
switch (today) {
case 'Monday':
print('星期一');
break;
case 'Tuesday':
print('星期二');
break;
}
//異常處理示例
try {
// ···
} on Exception catch (e) {
print('Exception details:\n $e');
} catch (e, s) {
print('Exception details:\n $e');
print('Stack trace:\n $s');
} finally {
print('Do some thing:\n');
}
}
54 .Getters 和 Setters 方法
class Rectangle {
num left;
num top;
num width;
num height;
Rectangle(this.left, this.top, this.width, this.height);
//獲取right值
num get right => left + width;
//設(shè)置right值 同時left也發(fā)生變化
set right(num value) => left = value - width;
//獲取bottom值
num get bottom => top + height;
//設(shè)置bottom值 同時top也發(fā)生變化
set bottom(num value) => top = value - height;
}
55. Text設(shè)置下劃線,虛線和刪除線
TextStyle(
//字體顏色
color: const Color(0xffff0000),
//文本裝飾器(刪除線)
decoration: TextDecoration.lineThrough,
//文本裝飾器顏色(刪除線顏色)
decorationColor: const Color(0xff000000),
//字體大小
fontSize: 18.0,
//字體樣式 是否斜體
fontStyle: FontStyle.italic,
//字體粗細
fontWeight: FontWeight.bold,
//文字間距
letterSpacing: 2.0,
)
// 下劃線
color: const Color(0xffff9900),
decoration: TextDecoration.underline,
// 虛線
decoration: TextDecoration.underline,
decorationStyle: TextDecorationStyle.dashed,
// 斜體
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold,
56.PopupMenuButton組件示例
//會控菜單項
enum ConferenceItem { AddMember, LockConference, ModifyLayout, TurnoffAll }
FlatButton(
onPressed: () {},
child: PopupMenuButton<ConferenceItem>(
onSelected: (ConferenceItem result) {},
itemBuilder: (BuildContext context) =>//菜單項構(gòu)造器
<PopupMenuEntry<ConferenceItem>>[
const PopupMenuItem<ConferenceItem>(//菜單項
value: ConferenceItem.AddMember,
child: Text('添加成員'),
),
const PopupMenuItem<ConferenceItem>(
value: ConferenceItem.LockConference,
child: Text('鎖定會議'),
),
const PopupMenuItem<ConferenceItem>(
value: ConferenceItem.ModifyLayout,
child: Text('修改布局'),
),
const PopupMenuItem<ConferenceItem>(
value: ConferenceItem.TurnoffAll,
child: Text('掛斷所有'),
),
],
),
)
57.TextField組件詳解
TextField(
//綁定controller
controller: controller,
//最大長度,設(shè)置此項會讓TextField右下角有一個輸入數(shù)量的統(tǒng)計字符串
maxLength: 30,
//最大行數(shù)
maxLines: 1,
//是否自動更正
autocorrect: true,
//是否自動對焦
autofocus: true,
//是否是密碼
obscureText: false,
//文本對齊方式
textAlign: TextAlign.center,
//輸入文本的樣式
style: TextStyle(fontSize: 26.0, color: Colors.green),
//文本內(nèi)容改變時回調(diào)
onChanged: (text) {
print('文本內(nèi)容改變時回調(diào) $text');
},
//內(nèi)容提交時回調(diào)
onSubmitted: (text) {
print('內(nèi)容提交時回調(diào) $text');
},
enabled: true, //是否禁用
decoration: InputDecoration(//添加裝飾效果
fillColor: Colors.grey.shade200,//添加灰色填充色
filled: true,
helperText: '用戶名',
prefixIcon: Icon(Icons.person),//左側(cè)圖標
suffixText: '用戶名'),//右側(cè)文本提示
)
58. 滑動刪除示例
效果圖

代碼
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
title: '滑動刪除示例',
home: new MyApp(),
));
}
class MyApp extends StatelessWidget {
//構(gòu)建30條列表數(shù)據(jù)
List<String> items = new List<String>.generate(30, (i) => "列表項 ${i + 1}");
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('滑動刪除示例'),
),
//構(gòu)建列表
body: new ListView.builder(
itemCount: items.length,//指定列表長度
itemBuilder: (context, index) {//構(gòu)建列表
//提取出被刪除的項
final item = items[index];
//返回一個可以被刪除的列表項
return new Dismissible(
key: new Key(item),
//被刪除回調(diào)
onDismissed: (direction) {
//移除指定索引項
items.removeAt(index);
//底部彈出消息提示當前項被刪除了
Scaffold.of(context).showSnackBar(
new SnackBar(content: new Text("$item 被刪除了")));
},
child: new ListTile(title: new Text('$item'),)
);
},
),
);
}
}
59 自定義字體添加及使用
-
1.放置字體資源
放置字體資源 2.在
pubspec.yaml配置路徑
fonts:
- family: myfont
fonts:
- asset: fonts/myfont.ttf
- 3.使用
Center(
child: new Text(
'你好 flutter',
style: new TextStyle(fontFamily: 'myfont',fontSize: 36.0),
),
)
- 效果圖

60.頁面跳轉(zhuǎn)返回數(shù)據(jù)
//壓棧操作并等待頁面返回操作
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondPage()),
);
//讀取并顯示返回值
Scaffold.of(context).showSnackBar(SnackBar(content: Text("$result")));
//出棧帶上參數(shù) 返回到上一個頁面
Navigator.pop(context, 'hi flutter');
61.fluro 企業(yè)級路由使用
- 導入依賴
fluro: ^1.5.0
- 組件封裝
// 1.定義Application類
import 'package:fluro/fluro.dart';
//定義Application類
class Application{
//使用靜態(tài)變量創(chuàng)建Router對象
static Router router;
}
// 2.定義路由集和handler
/// 2.1 handler
import 'package:fluro/fluro.dart';
import '../pages/second_page.dart';
import 'package:flutter/material.dart';
//創(chuàng)建Handler用來接收路由參數(shù)及返回第二個頁面對象
Handler secondPageHandler = Handler(
handlerFunc: (BuildContext context,Map<String,List<String>> params){
//讀取goodId參數(shù) first即為第一個數(shù)據(jù)
String goodId = params['goodId'].first;
return SecondPage(goodId);
}
);
/// 2.2 路由集
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'router_handler.dart';
//路由集
class Routes{
//根路徑
static String root = '/';
//第二個頁面路徑
static String secondPage = '/secondPage';
//配置路由對象
static void configureRoutes(Router router){
//沒有找到路由的回調(diào)方法
router.notFoundHandler = Handler(
handlerFunc: (BuildContext context,Map<String,List<String>> params){
print('error::: router 沒有找到');
}
);
//定義第二頁面路由的Handler
router.define(secondPage, handler: secondPageHandler);
}
}
- 第一個頁面
import 'package:flutter/material.dart';
import '../routers/application.dart';
import 'package:fluro/fluro.dart';
//第一個頁面
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Fluro路由導航示例"),
),
body: Center(
child: RaisedButton(
//點擊處理
onPressed: () {
_navigateToSecondPage(context);
},
child: Text('打開第二個頁面'),
),
),
);
}
//路由至第二個頁面
_navigateToSecondPage(BuildContext context) async {
//路由帶的參數(shù)
String goodId = '001';
//通過Application類里的路由router導航至第二個頁面 可指定頁面切換動畫類型
Application.router.navigateTo(context, "/secondPage?goodId=$goodId",transition: TransitionType.fadeIn).then((result) {//回傳值
//當?shù)诙€頁面返回時帶的參數(shù)為result值
if (result != null) {
print(result);
}
});
}
}
- 第二個頁面
import 'package:flutter/material.dart';
//第二個頁面
class SecondPage extends StatelessWidget {
//傳遞參數(shù)值
final String goodId;
SecondPage(this.goodId);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第二個頁面"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
//顯示傳遞參數(shù)值
Text(
'$goodId',
style: TextStyle(
fontSize: 28.0,
color: Colors.red,
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: () {
//出棧帶上參數(shù) 返回至第一個頁面
Navigator.pop(context, '第二個頁面返回參數(shù)($goodId)');
},
child: Text('點擊返回'),
),
),
],
),
),
);
}
}
- 配置路由
import 'package:flutter/material.dart';
import './routers/routes.dart';
import 'package:fluro/fluro.dart';
import './routers/application.dart';
import './pages/first_page.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
//創(chuàng)建路由對象
final router = Router();
//配置路由集Routes的路由對象
Routes.configureRoutes(router);
//指定Application的路由對象
Application.router = router;
return Container(
child: MaterialApp(
title: "Fluro路由導航示例",
debugShowCheckedModeBanner: false,
//生成路由的回調(diào)函數(shù),當導航的命名路由的時候,會使用這個來生成界面
onGenerateRoute: Application.router.generator,
//主頁指定為第一個頁面
home: FirstPage(),
),
);
}
}
62.數(shù)據(jù)庫操作('Sqlite')
模型
//客戶數(shù)據(jù)模型類
class Client {
//id
int id;
//姓名
String name;
//年齡
int age;
//性別
bool sex;
Client({this.id, this.name, this.age, this.sex,});
//將JSON數(shù)據(jù)轉(zhuǎn)換成數(shù)據(jù)模型
factory Client.fromMap(Map<String, dynamic> json) => Client(
id: json["id"],
name: json["name"],
age: json["age"],
sex: json["sex"] == 1,
);
//將數(shù)據(jù)模型轉(zhuǎn)換成JSON
Map<String, dynamic> toMap() => {
"id": id,
"name": name,
"age": age,
"sex": sex,
};
}
組件封裝
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'client.dart';
import 'package:sqflite/sqflite.dart';
//數(shù)據(jù)庫操作封裝類
class DBProvider {
DBProvider._();
static final DBProvider db = DBProvider._();
Database _database;
//獲取Database對象
Future<Database> get database async {
//使用單例模式創(chuàng)建Database對象
if (_database != null) {
return _database;
}
_database = await initDB();
return _database;
}
//初始化數(shù)據(jù)庫
initDB() async {
//獲取文檔目錄對象
Directory documentsDirectory = await getApplicationDocumentsDirectory();
//獲取默認數(shù)據(jù)庫位置(在Android上,它通常是data/data/<package_name>/databases,在iOS上,它是Documents目錄)
String path = join(documentsDirectory.path, "client.db");
//打開數(shù)據(jù)庫 傳入路徑 版本號 打開完成回調(diào)函數(shù)
return await openDatabase(path, version: 1, onOpen: (db) {},
onCreate: (Database db, int version) async {
//數(shù)據(jù)庫創(chuàng)建完成后創(chuàng)建Client表
await db.execute("CREATE TABLE Client ("
"id INTEGER PRIMARY KEY,"
"name TEXT,"
"age INTEGER,"
"sex BIT"
")");
});
}
//新增Client
insertClient(Client newClient) async {
final db = await database;
//獲取表中最大的id再加1作為新的id
var table = await db.rawQuery("SELECT MAX(id)+1 as id FROM Client");
int id = table.first["id"];
//向表中插入一條數(shù)據(jù)
var raw = await db.rawInsert(
"INSERT Into Client (id,name,age,sex)"
" VALUES (?,?,?,?)",
[id, newClient.name, newClient.age, newClient.sex]);
return raw;
}
//修改性別
updateSex(Client client) async {
final db = await database;
Client newClient = Client(
id: client.id,
name: client.name,
age: client.age,
sex: !client.sex);
//更新當前Client的性別
var res = await db.update("Client", newClient.toMap(),
where: "id = ?", whereArgs: [client.id]);
return res;
}
//更新Client
updateClient(Client newClient) async {
final db = await database;
var res = await db.update("Client", newClient.toMap(),
where: "id = ?", whereArgs: [newClient.id]);
return res;
}
//根據(jù)id獲取Client
getClient(int id) async {
final db = await database;
//根據(jù)id查詢表記錄
var res = await db.query("Client", where: "id = ?", whereArgs: [id]);
//將查詢返回的數(shù)據(jù)轉(zhuǎn)換為Client對象并返回
return res.isNotEmpty ? Client.fromMap(res.first) : null;
}
//獲取所有Client
Future<List<Client>> getAllClients() async {
final db = await database;
var res = await db.query("Client");
List<Client> list = res.isNotEmpty ? res.map((c) => Client.fromMap(c)).toList() : [];
return list;
}
//根據(jù)id刪除Client
deleteClient(int id) async {
final db = await database;
return db.delete("Client", where: "id = ?", whereArgs: [id]);
}
//刪除所有Client
deleteAll() async {
final db = await database;
db.rawDelete("Delete * from Client");
}
}
組件使用
// 獲取所有數(shù)據(jù)
DBProvider.db.getAllClients(),
//根據(jù)id刪除Client對象
DBProvider.db.deleteClient(item.id);
//更新性別
DBProvider.db.updateSex(item);
//隨機取測試數(shù)據(jù)中的一條數(shù)據(jù)作為Client對象
Client rnd = clients[math.Random().nextInt(clients.length)];
//新增加一個Client對象
await DBProvider.db.insertClient(rnd);
