组件
输入框
加背景颜色:decoration: InputDecoration( fillColor: Colors.white, filled: true,
修改宽高:修改TextField的高度可以通过decoration: InputDecoration的contentPadding进行修改
new TextField(
decoration: InputDecoration(
contentPadding: const EdgeInsets.symmetric(vertical: 10.0),
),
)
这种修改可以在没有prefixIcon的时候生效,如果加入prefixIcon,就会出现一个最小的高度,
这时,按照如上方法修改如果高度较小的时候会修改失败。
因而需要再TextField外层加一个BoxConstraints,代码如下:
new ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 25,
maxWidth: 200
),
child: new TextField(
decoration: InputDecoration(
contentPadding: const EdgeInsets.symmetric(vertical: 4.0),
hintText: '请输入搜索内容',
prefixIcon: Icon(Icons.search),
// contentPadding: EdgeInsets.all(10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
borderSide: BorderSide.none),
filled: true,
fillColor: Color(0xffaaaaaa),
),
),
),
maxHeight为最大高度,可酌情进行更改,实际修改的高度依旧是contentPadding这个属性。
maxWidth为最大宽度,可修改TextField的宽度。
较完整的输入框:
Container(
width: Adapt.dp(326),
height: Adapt.dp(95),
child: TextField(
maxLines:99,
// keyboardType: TextInputType.number,
style: TextStyle(
color: MyColors.black_00,
fontSize: MyFonts.mediumminus,
),
// textAlign: TextAlign.center,
decoration: InputDecoration(
//加白色背景
fillColor: MyColors.grey_f5,
filled: true,
// hintText: "最低值",
hintStyle: TextStyle(
color: MyColors.grey_99,
fontSize: MyFonts.small),
contentPadding: EdgeInsets.fromLTRB(Adapt.dp(5.0),
Adapt.dp(7.0), Adapt.dp(5.0), Adapt.dp(6.0)),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(Adapt.dp(7))),
borderSide: BorderSide.none),
),
),
),
加圆角
抽屉加圆角:
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: MyColors.white,
// borderRadius: BorderRadius.circular(Adapt.dp(20)),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(Adapt.dp(20)),
child: Drawer(
普通Container:
borderRadius: BorderRadius.only(topLeft: Radius.circular (Adapt.dp(20)) ,bottomLeft: Radius.circular (Adapt.dp(20),)),
加边框
decoration: BoxDecoration(
border: Border(right:BorderSide(
width: 1,color: Color(0xffddd)
))
),
弹出抽屉
`Scaffold.of() called with a context that does not contain a Scaffold.`
如果出现此错,用
GlobalKey<ScaffoldState> key=new GlobalKey();
void _handlerDrawerButton() {
key.currentState.openEndDrawer();
}
Widget build(BuildContext context) {
return Scaffold(
key: key,
backgroundColor: MyColors.grey_f5,
appBar: _appbar,
endDrawer: DrawerWidget(),或者Container(child:...)
body: Container(
),
);
}
普通的InkWell圆角按钮
InkWell(
onTap: () {
// _captchaPressed();//重置操作
},
child: Container(
height: Adapt.dp(44),
width: Adapt.dp(110),
alignment: Alignment(0, 0),
decoration: new BoxDecoration(
color: MyColors.white,
borderRadius: BorderRadius.all(
Radius.circular(Adapt.dp(22))),
border: new Border.all(width: 1, color: Colors.red),),
child: Text(
"重置",
style: TextStyle(
color: MyColors.text_font_black,
fontSize: MyFonts.large,
fontWeight: FontWeight.bold,)),
)),
网络版本:
Container(
margin: EdgeInsets.only(left: 40, top: 40),
child: new Material(
//INK可以实现装饰容器
child: new Ink(
//用ink圆角矩形
// color: Colors.red,
decoration: new BoxDecoration(
//背景
color: Colors.white,
//设置四周圆角 角度
borderRadius: BorderRadius.all(Radius.circular(25.0)),
//设置四周边框
border: new Border.all(width: 1, color: Colors.red),
),
child: new InkWell(
//圆角设置,给水波纹也设置同样的圆角
//如果这里不设置就会出现矩形的水波纹效果
borderRadius: new BorderRadius.circular(25.0),
//设置点击事件回调
onTap: () {},
child: Container(
//设置 child 居中
alignment: Alignment(0, 0),
height: 50,
width: 300,
child: Text("点击 Container 圆角边框"),
)),
),
),
),
WidgetSpan
Text.rich(
TextSpan(children: <InlineSpan>[
TextSpan(text: "xxxxxxxxxxxx嘤嘤嘤嘤嘤嘤晕晕晕晕晕晕晕晕晕晕晕晕晕晕晕晕晕晕晕晕晕晕晕x"),
WidgetSpan(
child: Container(
color: Colors.blue,
width: 30.0,
height: 100.0,
)),
TextSpan(text: "xxy"),
]),
overflow: TextOverflow.ellipsis,
maxLines: 2,
)
RaisedButton凸起按钮
RaisedButton:
Container(
width: Adapt.dp(265),
height: Adapt.dp(40),
child: RaisedButton(
color: MyColors.ls,
shape: RoundedRectangleBorder(
side: BorderSide.none,
borderRadius: BorderRadius.all(Radius.circular(25))),
child: Text(
test['complete'],
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
),
textColor: Theme.of(context).accentColor,
onPressed: () {
print('x');
})),
渲染列表数据
1.ListView
Expanded(
child: ListView.builder(
shrinkWrap: true, //为true可以解决子控件必须设置高度的问题
physics:NeverScrollableScrollPhysics(),//禁用滑动事件
itemBuilder: (context, index) {
return _buildList(list[index]);
},
itemCount: list.length,
),
)
Widget _buildList(item) {
return GestureDetector(
behavior: HitTestBehavior.translucent,
// onTap: CommonUtil.openPage(context, widget),
child: Container(
height: Adapt.dp(151),//也可以不加高度
margin: EdgeInsets.only(
bottom: Adapt.dp(13), right: Adapt.dp(13), left: Adapt.dp(13)),
padding: EdgeInsets.all(Adapt.dp(13)),
decoration: BoxDecoration(
color: MyColors.white, borderRadius: BorderRadius.circular(10)),
child: Row(
2.map
Expanded(
child: ListView(
children: getDistributorList(),
),
)
getDistributorList() {
return productNameList.map((item) {
return GestureDetector(
onTap: () {
},
behavior: HitTestBehavior.translucent,
child: Container(
padding: EdgeInsets.only(top: Adapt.dp(13)),
child: Row(
children: <Widget>[
Text(
item['name']??"",
style: TextStyle(
fontSize: MyFonts.mediumminus, color: MyColors.black_33),
)
],
),
),
);
}).toList();
}
上滑框showModalBottomSheet
-
无法直接设置圆角;
-
组件最多只能撑满半屏幕,再多就出界了;
showDialog以及showModalBottomSheet状态更新不刷新解决方法
cloud.tencent.com/developer/a…
在listView中为每一个list增添控制器
void initState() {
// TODO: implement initState
super.initState();
// this.getTotalPrice();
for (int i = 0; i < productList.length; i++) {
// controller.add (TextEditingController(text: "1")) ;
productList[i]["getNum"] = "1";
}
}
return productList.map((item){
var textEditingController = new TextEditingController(text: item["getNum"]);
TextField(
controller: textEditingController,
onChanged: (text){
// _onChanceCount(item,text);
// setState(() {会弹回输入框
item["getNum"]=text;
// });
},
dialog的一些思考
https://juejin.cn/post/6844903833575882759
https://github.com/liyabin1105/flutter_dialog/blob/master/lib/MyHomePage.dart
其他研究
flutter:教你自定义Dialog https://www.codercto.com/a/92081.html
https://blog.csdn.net/ulddfhv/article/details/91491918
https://www.jianshu.com/p/4bbbb5aa855d
ios风格弹框,带输入框
showCupertinoDialog(
context: context,
builder: (context) {
return CupertinoAlertDialog(
title: Text('提示'),
content: Card(
elevation: 0.0,
child: Column(
children: <Widget>[
Text('确认商品入库?'),
SizedBox(height: 10,),
Container(height: 26,
// color: Colors.grey.shade50,
// padding: EdgeInsets.only(top: ),
child: TextField(
controller: null,
style: TextStyle(
color: MyColors.black_00,
fontSize: MyFonts.mediumminus,
// fontWeight: FontWeight.bold,
),
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 16,top: 5,bottom: 4),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(Adapt.dp(13))),
borderSide: BorderSide.none),
hintText: '填写备注',
filled: true,
fillColor: Colors.grey.shade50),
),)
],
),
),
actions: <Widget>[
CupertinoDialogAction(
onPressed: () {
Navigator.pop(context);
},
child: Text('取消',style: TextStyle(color: MyColors.black_33),),
),
CupertinoDialogAction(
onPressed: () {
Navigator.pop(context);
},
child: Text('确定',style: TextStyle(color: Colors.red),),
),
],
);
});
'alertDialogLabel' was called on null.
参考https://juejin.cn/post/6844903763543588877 main.js
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
YabandLocalizationsDelegate.delegate,
const FallbackCupertinoLocalisationsDelegate(), //加入这个, 上面三个是我用来国际化的
],
class FallbackCupertinoLocalisationsDelegate
extends LocalizationsDelegate<CupertinoLocalizations> {
const FallbackCupertinoLocalisationsDelegate();
@override
bool isSupported(Locale locale) => true;
@override
Future<CupertinoLocalizations> load(Locale locale) =>
DefaultCupertinoLocalizations.load(locale);
@override
bool shouldReload(FallbackCupertinoLocalisationsDelegate old) => false;
}
捕获应用退出拦截弹出对话框
参考:www.cnblogs.com/pjl43/p/994…
Future<bool> _isSave(){
if(productList!=[]){
return
showDialog(
context: context,
builder: (context) =>
CustomDialog(
title: '提示',
content: '送货单未保存,确认退出?',
// confirmTextColor: Colors.red[400],
confirmCallback: () {
CommonUtil.closePage(context);
},
)
);
}else{
CommonUtil.closePage(context);
}
}
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _isSave,
child: Scaffold(
resizeToAvoidBottomPadding: false,
appBar: MyAppBar(
title: "新增送货单",
isBack: true,
backEvent: _isSave,//点图标返回结果不触发,结果按键就触发了
Tabbar不在顶部和底部的用法
import 'package:flutter/cupertino.dart';
import 'package:yilingpharmacy_doctor/common/CommonInsert.dart';
class MyPatientMainPage extends StatefulWidget {
@override
_MyPatientMainPageState createState() => _MyPatientMainPageState();
}
class _MyPatientMainPageState extends State<MyPatientMainPage>
with SingleTickerProviderStateMixin {
String dropdownValue = "在线";
var _tabController;
var _tabIndex = 0;
void initState() {
super.initState();
_tabController = new TabController(length: 2, vsync: this);
_tabController.addListener((){
setState(() {
_tabIndex = _tabController.index;
});
print(_tabController.index); });
}
@override
Widget build(BuildContext context) {
return Column(children: <Widget>[
// SizedBox(height: Adapt.screenH()*0.052,),
Container(
// alignment: Alignment.bottomLeft,
height: Adapt.screenH() * 0.153,
color: MyColors.lv,
padding: EdgeInsets.only(
top: Adapt.screenH() * 0.052,
),
child: Row(
children: <Widget>[
SizedBox(
width: Adapt.dp(10),
),
Container(
//两种设置头像的方法,这种会比较麻烦,
height: Adapt.dp(50),
width: Adapt.dp(50),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(Adapt.dp(25))),
child: LocalImageSelecter.getImage("b1_data_ic_yszczd"),
),
SizedBox(
width: Adapt.dp(11),
),
Container(
height: Adapt.dp(50),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(
height: 3,
),
Row(
children: <Widget>[
Text(
"刘海帆",
style: TextStyle(
fontSize: Adapt.dp(14),
color: Colors.white,
fontWeight: FontWeight.bold),
),
SizedBox(
width: Adapt.dp(13.5),
),
GestureDetector(
onTap: null,
child: Container(
width: Adapt.dp(54),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(Adapt.dp(2)),
),
child: Row(
children: <Widget>[
SizedBox(
width: Adapt.dp(6),
),
Text(
dropdownValue,
style: TextStyle(color: MyColors.lv),
),
SizedBox(
width: Adapt.dp(6),
),
LocalImageSelecter.getImage(
"b1_arrow_drop_green",
imageHeight: 10),
SizedBox(
width: Adapt.dp(5),
),
],
),
),
),
],
),
SizedBox(
height: Adapt.dp(12),
),
Row(
children: <Widget>[
Text(
'一级心理咨询师、中科院心理健康指导师',
style: TextStyle(
fontSize: Adapt.dp(12), color: Colors.white),
),
],
)
],
),
)
],
)),
Container(
// color: Colors.black,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
flex: 1,
child: TabBar(
indicator: const BoxDecoration(),//不加下横线
controller: _tabController,
tabs: <Widget>[
Tab(
child:
Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
"图文问诊",
style: _tabIndex==0?TextStyle(
color: MyColors.black_33,
fontSize: MyFonts.f_14,
fontWeight: FontWeight.bold):TextStyle(
color: MyColors.black_33,
fontSize: MyFonts.f_14,
),
),
_tabIndex==0?SizedBox(height: 12,):SizedBox(height: 15,),
_tabIndex==0?Container(color: MyColors.lv,height: 3,width: 20,):SizedBox()
],
)
),
Tab(
child:
Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
"问诊预约",
style: _tabIndex==1?TextStyle(
color: MyColors.black_33,
fontSize: MyFonts.f_14,
fontWeight: FontWeight.bold):TextStyle(
color: MyColors.black_33,
fontSize: MyFonts.f_14,
),
),
_tabIndex==1?SizedBox(height: 12,):SizedBox(height: 15,),
_tabIndex==1?Container(color: MyColors.lv,height: 3,width: 20,):SizedBox()
],
)
),
],
),
)
],
),
// body: ,
),
Expanded(
child: TabBarView(
controller: _tabController,
children: <Widget>[Text("xx"), Text("xx")],
),
)
]);
}
}

后期可以改造,animation controler 改造滑条
小bug:滑动过去,tab粗体效果显示有点慢
Android Studio
打开Android Studio主界面:
键盘操作Ctrl +Alt+S 打开设置界面
左侧搜索框输入keymap
比如想要查找类的名称补全,就可以在右边的搜索框内输入class name关键字
可以进行相关的修改
shortcut就是快捷键的意思
abbreviation是指缩写
其他
颜色添加
color: const Color(0xFF0099ff), or /Colors.grey/
透明: child:Opacity(
opacity: 0,
child: Container(
width: 100.0,
height: 100.0,
margin: EdgeInsets.all(20.0),
color: Color(0xffff0000),
),
),
color: Colors.transparent或者rgbo
延时加载
当setState() or markNeedsBuild() called during build.的时候用
void onDataChange2(val) {
if (mounted)
Future.delayed(Duration(milliseconds: 200)).then((e) {
setState(() {
isTab = val;
});
}
);
}
迁移androidX(runtime和usetime不一致时)
stackoverflow.com/questions/5…
- 在项目级别build.gradle将类路径更改为
com.android.tools.build:gradle:3.3.1。 - 在应用程序级别build.gradle将您的
compileSdkVersion和更改targetSdkVersion为28。 - 现在,右键单击flutter项目中的android目录,转到Flutter,然后单击Android Studio中的Open Android模块。在新窗口中打开项目。
- 现在,转到工具栏中的“重构”,然后单击“迁移到AndroidX”。
- 然后单击“执行重构”并等待gradle构建。
改gradle版本
android/gradle/wrapper/grade-wrapper.properties
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
全局定时调用请求
一般登陆之后用,我在登陆进去之后的页面用
class IndexPage extends StatefulWidget {
@override
_IndexPageState createState() => _IndexPageState();
}
class _IndexPageState extends State<IndexPage> {
void initState() {
super.initState();
countdown();
}
Timer countdownTimer;
void countdown() {
countdownTimer = new Timer.periodic(new Duration(seconds: 10), (timer) {
_getUnread();
});
}
_getUnread() async {//你想调的接口
if (LocalStorage.get(BaseCommon.USER_ID)!=null) {
var res = await HttpManager.netFetch(
context,
Address.findByAccountIdAndAlias(),
{"accountId": LocalStorage.get(BaseCommon.USER_ID)},
null,
null,
noTip: true);
if (res != null) {
LocalStorage.save("Unread", res.data['unread']);
LocalStorage.save("MessagePcketid", res.data['id']);
print('unread未读接口');
print(LocalStorage.get(("Unread")).toString());
print('MessagePcketid未读id接口');
print(LocalStorage.get(("MessagePcketid")).toString());
} else {
toast(BaseCommon.SERVER_ERROR);
}
}
}
定时器
验证码那样的
_countdownTimer =
new Timer.periodic(new Duration(seconds: 1), (timer) {
if (mounted) {
setState(() {
if (countDownNum > 1) {
countDownNum--;
} else {
showCountDown = false;
_countdownTimer.cancel();
_countdownTimer = null;
}
});
}
});
限定TextField输入内容
页面右上角的弹出菜单
Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: MyColors.bg,
appBar: MyAppBar(
title: test['myTeam'],
rightEvent: Container(height: 50,width: 30,child: new PopupMenuButton(
itemBuilder: (BuildContext context) => <PopupMenuEntry>[
PopupMenuItem(
child: GestureDetector(onTap: (){
ClipboardData data = new ClipboardData(text:'xx');
Clipboard.setData(data);
Toast.show(test['toast_copy_invitation_code_success'], context,
duration: Toast.LENGTH_SHORT, gravity: Toast.CENTER);
Navigator.pop(context);
},
child: Text(test['copy_invitation_code'],style: TextStyle(fontSize: 12),),)
),
PopupMenuItem(
child: GestureDetector(onTap: null,
child: Text(test['dissolveTeam'],style: TextStyle(fontSize: 12),),)
),
]),),
),
)
复制到粘贴板
GestureDetector(onTap: (){
ClipboardData data = new ClipboardData(text:'xx');
Clipboard.setData(data);
})
组件:ClipboardData.dart
import 'package:flutter/services.dart';
class ClipboardData {
/// Creates data for the system clipboard.
const ClipboardData({this.text});
/// Plain text variant of this clipboard data.
final String text;
}
class Clipboard {
Clipboard._();
static const String kTextPlain = 'text/plain';
/// Stores the given clipboard data on the clipboard.
///将ClipboardData中的内容复制的粘贴板
static Future<void> setData(ClipboardData data) async {
await SystemChannels.platform.invokeMethod<void>(
'Clipboard.setData',
<String, dynamic>{
'text': data.text,
},
);
}
}
//ClipboardData data = new ClipboardData(text:"1231231231231231");
//Clipboard.setData(data);
//showMyToast('已复制到粘贴板');
Flutter TabBarView切换页面防止刷新重置
还有一些bug,
进去他获取到了数据,切换tab再回来他才出现页面刷新渲染
是因为在渲染的时候加了if(mounted的判断,去掉就好
This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree
无视之。。
flutter中bottomNavigationBar切换组件保存状态方案
cloud.tencent.com/developer/a…
部分修改:
var _pages= [
new WebPage(),
new DiscoverPage(),
new UserPage(),
];
数据源
标准的ListView构造函数适用于小列表。 为了处理包含大量数据的列表,最好使用ListView.builder构造函数。
ListView的构造函数需要一次创建所有项目,但ListView.builder的构造函数不需要,它将在列表项滚动到屏幕上时创建该列表项。
https://flutterchina.club/cookbook/lists/long-lists/
final controller = new List<String>.generate(3, (i) => "controller$i");
//下面的报错https://blog.csdn.net/dpl12/article/details/92012226
final List<String> items;
items:new List<String>.generate(1000, (i)=>"item $i")/
延时刷新
_dataRefresh(){
Future.delayed(Duration(milliseconds: 200)).then((e) {
_list = [];
_getDataList();
});
}
打包
flutter build apk
打包需注意:
再打包 位置在-》不在原地方 android、app下,而在build/app下
C:\workFlutter\warehouse\build\app\outputs\apk\release
Flutter 修改App的名称和图标
图片上传(配合后端)
void _uploadPictures() async {
var list =
await MultiImagePicker.pickImages(maxImages: 9, enableCamera: true);
setState(() {
images = images+list;
});
for (var r in list) {
var t = await r.filePath;
await _upLoadImage(File(t));
}
}
_upLoadImage( File croppedFile) async {
String _path = croppedFile.path;
var _name = _path.substring(_path.lastIndexOf("/") + 1, _path.length);
String _suffix = _name.split(".").last.toLowerCase();
ContentType _contentType;
if (_suffix == "jpg") {
_contentType =ContentType("image", "jpeg");
} else if (_suffix == "png") {
_contentType =ContentType("image", 'png');
}
FormData _formData = new FormData.from({
"file": new UploadFileInfo(croppedFile, _name,contentType: _contentType)
});
String host = 'https://app.ji-hong.com.cn/api';
String url='/attachment/upload';
Dio dio = new Dio();
Response response =await dio.post("$host$url", data: _formData);
if (response.statusCode == 200) {
var resCode = response.data['code'];
if (resCode == 200) {
uploadimageList.add(response.data['data']);
print(response.data['data']);
} else if (resCode == 400) {
showToast(response.data['message']);
}
}
}
Widget buildGridView() {
return GridView.builder(
itemCount: images.length + 1,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, crossAxisSpacing: 4, mainAxisSpacing: 3),
itemBuilder: (BuildContext context, int index) {
return index != images.length
? Stack(children: <Widget>[
GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (_) => Center(
child: AssetThumb(
asset: images[index],
width: 300,
height: 300,
),
));
},
child: AssetThumb(
asset: images[index],
width: 105,
height: 105,
),
),
new Positioned(
right: 10,
top: 0.05,
child: new GestureDetector(
onTap: () {
setState(() {
if(uploadimageList.length == images.length){
images.remove(images[index]);
uploadimageList.removeAt(index);}else{
toast("等图片上传成功再删呗");
}
});
},
child: new Container(
decoration: new BoxDecoration(
color: Colors.black45,
shape: BoxShape.circle,
),
child: new Icon(
Icons.close,
color: Colors.white,
size: 20.0,
),
)))
])
: GestureDetector(
onTap: _uploadPictures,
child: Container(
alignment: Alignment.topLeft,
child: LocalImageSelecter.getImage('d_icon_sczp_n',
imageWidth: Adapt.dp(105),
imageHeight: Adapt.dp(105))));
});
}
//提交前的验证
_getDataList2() async {
if(uploadimageList.length!=images.length){toast("图片未上传完毕,稍等。。");return;}
dart语法小记
添加请求后端返回数据
这个加的是数组_list.addAll(res.data);
这个加的是map_list.add(list);
这样去获取数据,data是map对象res.data['productDTOList']
map中是否包含某keyif (res.data.containsKey("productDTOList"))
判断数组是否为空时,应该用length判断if(_list.length!=0){