一直觉得自己写的不是技术,而是情怀,一个个的教程是自己这一路走来的痕迹。靠专业技能的成功是最具可复制性的,希望我的这条路能让你们少走弯路,希望我能帮你们抹去知识的蒙尘,希望我能帮你们理清知识的脉络,希望未来技术之巅上有你们也有我。
效果
本章目标:
1.获取网络数据,赋值到第一个视图里面
商品详情获取回来的网络数据
{"result":{"_id":"5a0425bc010e711234661439","title":"磨砂牛皮男休闲鞋-有属性","cid":"5a042480010e711234661436","price":"688","old_price":"368","is_best":1,"is_hot":"1","is_new":"1","attr":[{"cate":"鞋面材料","list":["牛皮 "]},{"cate":"闭合方式","list":["系带"]},{"cate":"颜色","list":["红色","白色","黄色"]}],"status":1,"pic":"public\\upload\\RinsvExKu7Ed-ocs_7W1DxYO.png","content":"<p style=\"margin: 1.12em 0px; padding: 0px; text-align: center; line-height: 1.4; color: rgb(64, 64, 64); font-family: tahoma, arial, 宋体, sans-serif; font-size: 14px;\"><strong>非凡舒适,经久耐穿,融入飞翔元素,让你无论身处何处,都备受瞩目</strong><br /><br /><img alt=\"\" src=\"https://img30.360buyimg.com/popWaterMark/jfs/t7390/58/3849479320/166969/b8c17cad/59fabd2fNcd1ed823.jpg\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: middle;\" /></p><p style=\"margin: 1.12em 0px; padding: 0px; text-align: center; line-height: 1.4; color: rgb(64, 64, 64); font-family: tahoma, arial, 宋体, sans-serif; font-size: 14px;\"><img class=\"img-ks-lazyload\" alt=\"\" src=\"https://img30.360buyimg.com/imgzone/jfs/t10504/182/2465321261/89642/619c161b/59f831b8Nb84a4b96.jpg\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: top; animation: ks-fadeIn 350ms linear 0ms 1 normal both; opacity: 1; float: none;\" align=\"absmiddle\" /><img class=\"img-ks-lazyload\" alt=\"\" src=\"https://img14.360buyimg.com/imgzone/jfs/t9772/268/2466805940/61723/34d37efb/59f831cdNded68405.jpg\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: top; animation: ks-fadeIn 350ms linear 0ms 1 normal both; opacity: 1; float: none;\" align=\"absmiddle\" /><img class=\"img-ks-lazyload\" alt=\"\" src=\"https://img14.360buyimg.com/imgzone/jfs/t9775/81/2512315198/70050/331ea0d4/59f831cdN3c6df0aa.jpg\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: top; animation: ks-fadeIn 350ms linear 0ms 1 normal both; opacity: 1; float: none;\" align=\"absmiddle\" /><img class=\"img-ks-lazyload\" alt=\"\" src=\"https://img14.360buyimg.com/imgzone/jfs/t11653/222/774240663/68769/d8e9ff98/59f831ceN35a4273f.jpg\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: top; animation: ks-fadeIn 350ms linear 0ms 1 normal both; opacity: 1; float: none;\" align=\"absmiddle\" /><img class=\"img-ks-lazyload\" alt=\"\" src=\"https://img12.360buyimg.com/imgzone/jfs/t10636/218/2491518591/68633/ac6c5b05/59f831caN262904b1.jpg\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: top; animation: ks-fadeIn 350ms linear 0ms 1 normal both; opacity: 1; float: none;\" align=\"absmiddle\" /><img class=\"img-ks-lazyload\" alt=\"\" src=\"https://img14.360buyimg.com/imgzone/jfs/t10732/210/2485945643/66258/7276a664/59f831caNd20e2b4a.jpg\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: top; animation: ks-fadeIn 350ms linear 0ms 1 normal both; opacity: 1; float: none;\" align=\"absmiddle\" /></p><img class=\"desc_anchor img-ks-lazyload\" id=\"desc-module-2\" alt=\"\" src=\"https://img10.360buyimg.com/imgzone/jfs/t11101/10/781218477/43/9acceab1/59f831aaN8687189b.gif\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: top; text-align: center; height: 1px; display: block; clear: both; animation: ks-fadeIn 350ms linear 0ms 1 normal both; opacity: 1; color: rgb(64, 64, 64); font-family: tahoma, arial, 宋体, sans-serif; font-size: 14px; line-height: 21px;\" /><p style=\"margin: 1.12em 0px; padding: 0px; text-align: center; line-height: 1.4; color: rgb(64, 64, 64); font-family: tahoma, arial, 宋体, sans-serif; font-size: 14px;\"><br /></p><p style=\"margin: 1.12em 0px; padding: 0px; text-align: center; line-height: 1.4; color: rgb(64, 64, 64); font-family: tahoma, arial, 宋体, sans-serif; font-size: 14px;\"><img class=\"img-ks-lazyload\" alt=\"\" src=\"https://img10.360buyimg.com/imgzone/jfs/t10399/103/2508090813/543802/dcc5fa46/59f831d4N87a2bc5d.jpg\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: top; animation: ks-fadeIn 350ms linear 0ms 1 normal both; opacity: 1; float: none;\" align=\"absmiddle\" /></p>","cname":"男鞋","sub_title":"非凡舒适,经久耐穿,融入飞翔元素,让你无论身处何处,都备受瞩目","salecount":275}}
1.编写数据模型
class ProductContentModel {
ProductContentitem result;
ProductContentModel({this.result});
ProductContentModel.fromJson(Map<String, dynamic> json) {
result =
json['result'] != null ? new ProductContentitem.fromJson(json['result']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.result != null) {
data['result'] = this.result.toJson();
}
return data;
}
}
class ProductContentitem {
String sId;
String title;
String cid;
Object price;
Object oldPrice;
Object isBest;
Object isHot;
Object isNew;
Object status;
Object pic;
String content;
String cname;
List<Attr> attr;
String subTitle;
Object salecount;
ProductContentitem(
{this.sId,
this.title,
this.cid,
this.price,
this.oldPrice,
this.isBest,
this.isHot,
this.isNew,
this.status,
this.pic,
this.content,
this.cname,
this.attr,
this.subTitle,
this.salecount});
ProductContentitem.fromJson(Map<String, dynamic> json) {
sId = json['_id'];
title = json['title'];
cid = json['cid'];
price = json['price'];
oldPrice = json['old_price'];
isBest = json['is_best'];
isHot = json['is_hot'];
isNew = json['is_new'];
status = json['status'];
pic = json['pic'];
content = json['content'];
cname = json['cname'];
if (json['attr'] != null) {
attr = new List<Attr>();
json['attr'].forEach((v) {
attr.add(new Attr.fromJson(v));
});
}
subTitle = json['sub_title'];
salecount = json['salecount'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['_id'] = this.sId;
data['title'] = this.title;
data['cid'] = this.cid;
data['price'] = this.price;
data['old_price'] = this.oldPrice;
data['is_best'] = this.isBest;
data['is_hot'] = this.isHot;
data['is_new'] = this.isNew;
data['status'] = this.status;
data['pic'] = this.pic;
data['content'] = this.content;
data['cname'] = this.cname;
if (this.attr != null) {
data['attr'] = this.attr.map((v) => v.toJson()).toList();
}
data['sub_title'] = this.subTitle;
data['salecount'] = this.salecount;
return data;
}
}
class Attr {
String cate;
List<String> list;
Attr({this.cate, this.list});
Attr.fromJson(Map<String, dynamic> json) {
cate = json['cate'];
list = json['list'].cast<String>();
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['cate'] = this.cate;
data['list'] = this.list;
return data;
}
}
2.回到详情商品页 ProductContent
导入头文件
import '../config/Config.dart';
import 'package:dio/dio.dart';
import '../model/ProductContentModel.dart';
import '../widget/LoadingWidget.dart';
写到详情页的主控制器里面
List _productContentList=[];
@override
void initState() {
// TODO: implement initState
super.initState();
this._getContentData();
}
_getContentData() async{
var api ='${Config.domain}api/pcontent?id=${widget.arguments['id']}';
print(api);
var result = await Dio().get(api);
var productContent = new ProductContentModel.fromJson(result.data);
setState(() {
this._productContentList.add(productContent.result);
});
}
3.修改下面的代码
3.2.判断获取回来有数据才把数据传递进去2.把获取回来的数据传递到商品控件里面
body: this._productContentList.length>0?Stack(
children: <Widget>[
TabBarView(
children: <Widget>[
ProductContentFirst(this._productContentList),
ProductContentSecond(this._productContentList),
ProductContentThird()
],
),
Positioned(
width: ScreenAdapter.width(750),
height: ScreenAdapter.width(88),
):LoadingWidget(),
3.3.回到详情页编写接收数据的变量
导入
import '../../config/Config.dart';
class ProductContentSecond extends StatefulWidget {
final List _productContentList;
ProductContentSecond(this._productContentList,{Key key}) : super(key: key);
_ProductContentSecondState createState() => _ProductContentSecondState();
}
3.4.回到商品页编写接收数据的变量
ProductContentFirst文件中导入
import '../../model/ProductContentModel.dart';
import '../../config/Config.dart';
class ProductContentFirst extends StatefulWidget {
final List _productContentList;//--------------------------------
ProductContentFirst(this._productContentList, {Key key}) : super(key: key);//--------------------------------
_ProductContentFirstState createState() => _ProductContentFirstState();
}
class _ProductContentFirstState extends State<ProductContentFirst> {
ProductContentitem _productContent;//--------------------------------
@override
void initState() {
super.initState();
this._productContent = widget._productContentList[0];
}
3.5.动态给商品页的属性赋值
@override
Widget build(BuildContext context) {
//--------------------------------------------
//处理图片
String pic = Config.domain + this._productContent.pic;
pic = pic.replaceAll('\\', '/');
//--------------------------------------------
return Container(
child: ListView(
children: <Widget>[
AspectRatio(
aspectRatio: 16 / 12,
//--------------------------------------------
child: Image.network("${pic}", fit: BoxFit.cover),
//--------------------------------------------
),
//标题
Container(
padding: EdgeInsets.only(top: 10),
child: Text
//--------------------------------------------
("${this._productContent.title}",
//--------------------------------------------
style: TextStyle(
color: Colors.black87, fontSize: ScreenAdapter.size(36))),
),
Container(
padding: EdgeInsets.only(top: 10),
child: Text(
//--------------------------------------------
"${this._productContent.subTitle}",
//--------------------------------------------
style: TextStyle(
color: Colors.black54,
fontSize: ScreenAdapter.size(28)))),
//价格
children: <Widget>[
Text("特价: "),
//--------------------------------------------
Text("¥${this._productContent.price}",
//--------------------------------------------
children: <Widget>[
Text("原价: "),
//--------------------------------------------
Text("¥${this._productContent.oldPrice}",
//--------------------------------------------
3.6.为底部弹框赋值
3.6.0先删除代码
代码在 _attrBottomSheet 封装里面 搜索 mainAxisAlignment: MainAxisAlignment.center,
创建数组
List _attr = [];
3.6.1为数组赋值
写在 _ProductContentFirstState 里面
this._attr = this._productContent.attr;
3.6.2封装两个方法
List<Widget> _getAttrItemWidget(attrItem) {
List<Widget> attrItemList = [];
attrItem.list.forEach((item) {
attrItemList.add(Container(
margin: EdgeInsets.all(10),
child: Chip(
label: Text("${item}"),
padding: EdgeInsets.all(10),
),
));
});
return attrItemList;
}
//封装一个组件 渲染attr
List<Widget> _getAttrWidget() {
List<Widget> attrList = [];
this._attr.forEach((attrItem) {
attrList.add(Wrap(
children: <Widget>[
Container(
width: ScreenAdapter.width(120),
child: Padding(
padding: EdgeInsets.only(top: ScreenAdapter.height(22)),
child: Text("${attrItem.cate}: ",
style: TextStyle(fontWeight: FontWeight.bold)),
),
),
Container(
width: ScreenAdapter.width(590),
child: Wrap(
children: _getAttrItemWidget(attrItem),
),
)
],
));
});
return attrList;
}
3.6.3在底部弹出框调用上面封装的方法。
padding: EdgeInsets.all(ScreenAdapter.width(20)),
child: ListView(
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: _getAttrWidget()
)