商品详情页完成--看看效果:
1111.gif商品详情页布局
商品详情页一般都是这个商城app中布局最多的一个界面,也是各种交互比较多的界面,整整写了一天才写完(其实还没完,后面有些无关紧要的图片就没有写了)
还是一点来吧
首先是路由配置和数据获取
路由配置:
Handler detailsHandler = Handler(
handlerFunc: (BuildContext context,Map<String,List<String>> params){
String itemCode = params["itemCode"].first;//传递请求参数
print("传递的itemCode是: ${itemCode}");
return DetailsPage(itemCode);
}
static String detailsPage = "/detailsPage";
router.define(detailsPage,handler: detailsHandler);
//使用:
onTap: (){
Application.router.navigateTo(context, "/detailsPage?itemCode=${sectionListItem.productCode}");
},
数据获取:
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../provide/details_provide.dart';
import './detailsSubWidget/top_swiper_widget.dart';
import './detailsSubWidget/detailsBottom_widget.dart';
import './detailsSubWidget/detailsTitle_widget.dart';
import './detailsSubWidget/detailsDescribe_widget.dart';
import './detailsSubWidget/detailsDelivery_widget.dart';
import './detailsSubWidget/detailsEvaluate_widget.dart';
import './detailsSubWidget/detailsCompany_widget.dart';
import './detailsSubWidget/detailsImgText_widget.dart';
class DetailsPage extends StatelessWidget {
String itemCode;
DetailsPage(this.itemCode);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
leading: IconButton(
icon: Icon(Icons.arrow_back,color: Colors.black,),
onPressed: (){
Navigator.pop(context);
},
),
title: Provide<DetailsPageProvide>(
builder: (context,child,val){
return Text(val.datas.itemName,
style: TextStyle(color:Colors.black),
);
},
)
),
body: FutureBuilder(
future: _getDetailPage(context),
builder: (context,snapshot){
if(snapshot.hasData){
return Stack(
children: <Widget>[
Container(
color: Colors.black12,
child: ListView(
children: <Widget>[
TopSwiper(),
DetailsTitle(),
SizedBox(height: 8.0,),
DetailsDescribe(),
SizedBox(height: 8.0,),
DetailsDelivery(),
SizedBox(height: 8.0,),
DetailsEvaluate(),
SizedBox(height: 8.0,),
DetailsCompany(),
SizedBox(height: 8.0,),
DetailsImgText(),
SizedBox(height: 80.0,)
],
),
),
Positioned(
bottom: 0,
left: 0,
child: DetailsBottom(),
)
],
);
}else{
return Center(
child: Text("暂无数据"),
);
}
}
)
);
}
Future _getDetailPage(BuildContext context) async{
await Provide.value<DetailsPageProvide>(context).getDetailsPageData(itemCode);
return "加载完成";
}
}
从ListView中就是我拆分的详情页部分的各个组件。下面还是将各个组件中的代码贴出来。
顶部图片轮播
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../../provide/details_provide.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
class TopSwiper extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Provide<DetailsPageProvide>(
builder: (context,child,val){
var coverImages = val.datas.coverImages;
return Container(
color: Colors.white,
height: MediaQuery.of(context).size.height*0.6,
child: Swiper(
itemBuilder: (BuildContext context,int index){
return Image.network("${coverImages[index]}");
},
onTap: (index){
print("点击了轮播组件:${index}");
},
itemCount: coverImages.length,
pagination: buildSwiperPagintion(),
autoplay: true,
),
);
},
);
}
buildSwiperPagintion(){
return SwiperPagination(
builder: FractionPaginationBuilder(
color: Colors.white,
activeColor: Colors.orange
)
);
}
}
这个轮播插件还是挺好用的,就是这个Page指示器和app上的不一样,由于这个插件只提供了两种样式,如果想要和app中的一样需要自定义这个SwiperPagination, 后面完成后,来试试自己自定义这个东东。
顶部标题和价格
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../../provide/details_provide.dart';
import '../../model/details_model.entity.dart';
class DetailsTitle extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Provide<DetailsPageProvide>(
builder: (context,child,val){
var datas = val.datas;
return Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border(
top: BorderSide(width: 1,color: Colors.black12),
bottom: BorderSide(width: 1,color:Colors.black12)
)
),
child: Padding(
padding: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 10.0),
child: Container(
child: Column(
children: <Widget>[
_buildTitle(datas.itemName,datas.introduction),
SizedBox(height: 15.0,),
_buildPrice(datas),
],
),
),
),
);
},
);
}
//标题
Widget _buildTitle(String name,String introduction){
return Container(
child: Row(
children: <Widget>[
Expanded(
flex: 8,
child: Container(
child: Text(
"${name}--${introduction}",
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
),
Expanded(
flex: 2,
child: Container(
alignment: Alignment.centerRight,
child:Icon(Icons.star_border),
)
)
],
),
);
}
//价格
Widget _buildPrice(DetailsModelDatas datas){
return Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: <Widget>[
Text(
"¥${datas.price}",
style: TextStyle(
color:Colors.orangeAccent,
fontSize: 24.0
),
),
SizedBox(width: 5.0,),
Text(
"¥${datas.linePrice}",
style: TextStyle(
color: Colors.black26,
decoration: TextDecoration.lineThrough
),
)
],
),
Container(
alignment: Alignment.centerRight,
child: Text(datas.sale),
)
],
),
);
}
}
这个没什么好说的,说说这个Icon吧,这里有这个flutter自带Icon图标图文对应的网址,里面的图标已经算非常全面了,用的时候可以找找看看
描述部分
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../../provide/details_provide.dart';
import '../../model/details_model.entity.dart';
class DetailsDescribe extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Provide<DetailsPageProvide>(
builder: (context,child,val){
var datas = val.datas;
return Container(
color: Colors.white,
child: Column(
children: <Widget>[
_buildFlowers(datas),
_buildMaterial(datas),
_buildExpansionpanel(datas)
],
),
);
},
);
}
//花语
Widget _buildFlowers(DetailsModelDatas datas){
return Padding(
padding: EdgeInsets.symmetric(horizontal: 10.0),
child: Container(
padding: EdgeInsets.only(top: 10.0),
child: Row(
children: <Widget>[
Expanded(
flex: 1,
child: Container(
alignment: Alignment.topLeft,
child: Text("花语",
style:TextStyle(
fontWeight:FontWeight.w600
)
),
),
),
Expanded(
flex: 9,
child: Container(
padding: EdgeInsets.only(bottom: 8.0),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(width: 1,color:Colors.black12)
)
),
child: Text(
datas.huaYu,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
)
)
],
),
),
);
}
//材料
Widget _buildMaterial(DetailsModelDatas datas){
return Padding(
padding: EdgeInsets.symmetric(horizontal: 10.0),
child: Container(
padding: EdgeInsets.only(top: 10.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
flex: 1,
child: Container(
padding: EdgeInsets.only(bottom: 8.0),
alignment: Alignment.topLeft,
child: Text("材料",
style:TextStyle(
fontWeight:FontWeight.w600
)
),
),
),
Expanded(
flex: 9,
child: Container(
padding: EdgeInsets.only(bottom: 8.0),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(width: 1,color:Colors.black12)
)
),
child: Text(
datas.stuff,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
)
)
],
),
),
);
}
//配送
Widget _buildExpansionpanel(DetailsModelDatas datas){
return Padding(
padding: EdgeInsets.symmetric(horizontal: 0.0),
child: Container(
child: Container(
margin: EdgeInsets.all(0.0),
padding: EdgeInsets.all(0.0),
child: ExpansionTile(
title: ListTile(
contentPadding: EdgeInsets.all(0),
leading: Text("配送",
style:TextStyle(
fontSize: 14.0,
fontWeight:FontWeight.w600
)
),
title: Text(
datas.deliveryArea,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style:TextStyle(
fontSize: 14.0,
)
),
),
children: <Widget>[
Container(
padding: EdgeInsets.only(bottom: 10.0),
child: Text(datas.deliveryArea),
)
],
),
)
)
);
}
}
描述部分就注意一下这个ExpansionTile可展开的ListTile组件,还是比较常用的.
选择/配送
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../../provide/details_provide.dart';
import '../../model/details_model.entity.dart';
import 'package:city_pickers/city_pickers.dart';
class DetailsDelivery extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Provide<DetailsPageProvide>(
builder: (context,child,val){
var datas = val.datas;
return Container(
color: Colors.white,
child: Column(
children: <Widget>[
datas.itemSKUs != null ? _buildFlowers(context,datas) : SizedBox(height: 0.1,),
_buildPeisong(context,"送至", "请选择配送地区")
],
),
);
},
);
}
Widget _buildFlowers(BuildContext context,DetailsModelDatas datas){
return Padding(
padding: EdgeInsets.symmetric(horizontal: 10.0),
child: Container(
padding: EdgeInsets.only(top: 10.0),
child: Row(
children: <Widget>[
Expanded(
flex: 1,
child: Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(bottom: 8.0),
child: Text("已选",
style:TextStyle(
fontWeight:FontWeight.w600
)
),
),
),
Expanded(
flex: 8,
child: Container(
padding: EdgeInsets.only(bottom: 8.0),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(width: 1,color:Colors.black12)
)
),
child: Text(
datas.itemName,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
)
),
Expanded(
flex: 1,
child: Container(
alignment: Alignment.centerRight,
child: InkWell(
onTap: ()=> _onBottomSheet(context,datas),
child: Icon(Icons.more_horiz,
size: 30.0,
),
),
),
)
],
),
),
);
}
//配送
Widget _buildPeisong(BuildContext context,String title,String des){
return Padding(
padding: EdgeInsets.symmetric(horizontal: 10.0),
child: Container(
padding: EdgeInsets.only(top: 10.0),
child: Row(
children: <Widget>[
Expanded(
flex: 1,
child: Container(
padding: EdgeInsets.only(bottom: 8.0),
alignment: Alignment.centerLeft,
child: Text(title,
style:TextStyle(
fontWeight:FontWeight.w600
)
),
),
),
Expanded(
flex: 8,
child: Container(
padding: EdgeInsets.only(bottom: 8.0),
child: Text(
des,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
)
),
Expanded(
flex: 1,
child: Container(
alignment: Alignment.centerRight,
child: InkWell(
onTap: () async {
print("选择配置地址");
Result result = await CityPickers.showCityPicker(
context: context,
);
print("选择地址结果是: ${result}");
},
child: Icon(Icons.more_horiz,
size: 30.0,
),
),
),
)
],
),
),
);
}
//商品选择弹出框
void _onBottomSheet(BuildContext context,DetailsModelDatas datas){
showModalBottomSheet(
context: context,
builder: (context){
return Stack(
children: <Widget>[
Container(
color: Color(0xFF737373),
height: MediaQuery.of(context).size.height * 0.55,
child: Container(
color: Colors.white,
child: Column(
children: <Widget>[
_buildBottomSelectGood(context, datas)
],
)
),
),
Positioned(
bottom: 0,
left: 0,
child: Container(
height: 60.0,
child: Row(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width/2,
color: Color.fromRGBO(45, 60, 49, 1.0),
alignment: Alignment.center,
child: Text(
"加入购物车",
style:TextStyle(
color:Colors.white,
fontSize: 20.0
)
),
),
Container(
width: MediaQuery.of(context).size.width/2,
color: Colors.orangeAccent,
alignment: Alignment.center,
child: Text(
"立即购买",
style:TextStyle(
color:Colors.white,
fontSize: 20.0
)
),
)
],
),
)
)
],
);
}
);
}
//商品选择弹出框UI
Widget _buildBottomSelectGood(BuildContext context,DetailsModelDatas datas){
return Container(
child:Column(
children: <Widget>[
_buildGoodsShowTop(context, datas),
_buildChangeGoods(context, datas),
SizedBox(height: 20.0,),
_buildGoodsCount(context),
],
)
);
}
//头部商品展示
Widget _buildGoodsShowTop(BuildContext context,DetailsModelDatas datas){
return Container(
padding: EdgeInsets.fromLTRB(15.0, 15.0, 15.0, 10.0),
child:Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width / 4,
height: MediaQuery.of(context).size.width / 4,
decoration: BoxDecoration(
border: Border.all(width: 1,color:Colors.black12),
borderRadius: BorderRadius.circular(3.0)
),
child: Image.network(datas.coverImages[0]),
),
Container(
padding: EdgeInsets.only(top: 15.0),
width: MediaQuery.of(context).size.width / 2,
alignment: Alignment.centerLeft,
child:Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
alignment: Alignment.centerLeft,
child: Text("¥${datas.price}",
style: TextStyle(
fontSize: 20.0,
color: Colors.deepOrange
),
),
),
SizedBox(height: 3.0,),
Container(
alignment: Alignment.centerLeft,
child: Text("已选 ${datas.itemName}"),
)
],
),
),
Container(
child: InkWell(
onTap: (){
print("关闭底部弹窗");
Navigator.pop(context);
},
child: Container(
alignment: Alignment.topRight,
child: Icon(Icons.close,
size: 30.0,
),
)
),
)
],
)
);
}
//商品切换选择
Widget _buildChangeGoods(BuildContext context,DetailsModelDatas datas){
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0),
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
alignment: Alignment.centerLeft,
child: Text("选择"),
),
SizedBox(height: 10.0,),
Wrap(
alignment: WrapAlignment.spaceBetween,
spacing: 10.0,
runSpacing: 10.0,
children: _buildChangeList(context, datas.itemSKUs)
)
],
),
),
);
}
//选择列表
List<Widget> _buildChangeList(BuildContext context,List<DetailsModelDatasItemsku> itemList){
List<Widget> list = new List();
for(var i = 0; i < itemList.length; i++){
list.add(
Container(
width: (MediaQuery.of(context).size.width - 60.0)/4,
height: 35.0,
color: Colors.black12,
alignment: Alignment.center,
child: InkWell(
onTap: (){},
child: Text(itemList[i].optionName),
),
)
);
}
return list;
}
//商品数量加减
Widget _buildGoodsCount(BuildContext context){
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0),
child: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text("数量"),
_addOrReduceWidget(context)
],
),
),
);
}
//商品加减小组件
Widget _addOrReduceWidget(BuildContext context){
return Container(
width: MediaQuery.of(context).size.width / 4.2,
height: 30.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
//减
Container(
width: 24.0,
height: 24.0,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.black26,
borderRadius: BorderRadius.circular(12.0)
),
child: Text("-",
style:TextStyle(
fontSize: 18.0,
color:Colors.white
)
),
),
Container(
child: Text("1"),
),
Container(
width: 24.0,
height: 24.0,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.black26,
borderRadius: BorderRadius.circular(12.0)
),
child: Text("+",
style:TextStyle(
fontSize: 18.0,
color:Colors.white
)
),
),
],
),
);
}
}
这里面代码就比较多了,主要是我将这个选择商品规格和数量的底部sheet和这个省市区选择放在了一起了。 这里面注意这个底部弹出框是用这个: showModalBottomSheet,非常好用,不像以前原生要做个底部自定义弹窗(唉)。 还有就是我的省市区选择是用的国人写的插件city_pickers,挺好的,简单方便。
订单评价
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../../provide/details_provide.dart';
import '../../model/details_model.entity.dart';
class DetailsEvaluate extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Provide<DetailsPageProvide>(
builder: (context,child,val){
var datas = val.datas;
return Container(
color: Colors.white,
child:
//判断是否有评价
datas.comments != null ?
Column(
children: <Widget>[
_buildTopTitle(context, datas),
_buildEvaluates(context, datas.comments.itemComments),
SizedBox(height: 10.0,),
Container(
alignment: Alignment.center,
child: RaisedButton(
padding: EdgeInsets.fromLTRB(15.0, 10.0, 15.0, 10.0),
onPressed: (){},
child: Text("查看更多评价"),
),
)
],
):Container(
child: Center(
child: Text("暂无评价"),
),
)
);
},
);
}
//顶部评价
Widget _buildTopTitle(BuildContext context,DetailsModelDatas datas){
return Padding(
padding: EdgeInsets.all(10.0),
child: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
child: Text("订单评价",
style:TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.w600
)
),
),
Container(
child: Text(
"最近已有${datas.comments.commentCount}条评价>"
),
)
],
),
),
);
}
//评价列表
Widget _buildEvaluates(BuildContext context,List<DetailsModelDatasCommantsItemcommants> itemComments){
return Container(
child: Column(
children: _buildEvaluateList(context, itemComments),
),
);
}
List<Widget> _buildEvaluateList(BuildContext context,List<DetailsModelDatasCommantsItemcommants> itemComments){
List<Widget> list = new List();
for(var i = 0; i < itemComments.length; i++){
list.add(
_buildEvaluateItem(context, itemComments[i])
);
}
return list;
}
//评价项
Widget _buildEvaluateItem(BuildContext context,DetailsModelDatasCommantsItemcommants commant){
return Container(
padding: EdgeInsets.fromLTRB(10.0, 20.0, 10.0, 10.0),
decoration: BoxDecoration(
border: Border(
top: BorderSide(width: 1,color: Colors.black12)
)
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: <Widget>[
Container(
width: 30.0,
height: 30.0,
child: ClipOval(
child: Image.network(commant.userHeadImg),
),
),
SizedBox(width: 3.0,),
Text(commant.nickName)
],
),
Container(
child: _buildStars(context,commant.commentGrade),
)
],
),
),
SizedBox(height: 10.0,),
//评价语
Container(
width: MediaQuery.of(context).size.width * 0.8,
alignment: Alignment.centerLeft,
child: Text(
commant.commentContent
),
),
SizedBox(height: 10.0,),
//评价图片
commant.commentImgs != null ? Container(
alignment: Alignment.centerLeft,
width: 150.0,
child: Image.network(commant.commentImgs[0],
fit: BoxFit.fitWidth,
),
): SizedBox(height: 2.0,),
SizedBox(height: 8.0,),
//地址
Container(
child: Row(
children: <Widget>[
Container(
child: Icon(Icons.place,
size: 24.0,
color: Colors.black45,
),
),
Container(
child: Text(commant.commentAddress,
),
)
],
),
)
],
),
);
}
Widget _buildStars(BuildContext context,int commentGrade){
List<Widget> lists = List();
for(var i = 0; i < commentGrade; i++){
lists.add(
Container(
child: Row(
children: <Widget>[
Icon(Icons.star,
color: Colors.orangeAccent,
size: 20.0,
),
SizedBox(width: 2.0,),
],
),
)
);
}
return Container(
child: Row(
children: lists
),
);
}
}
权当练习布局了
为什么选择我们
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../../provide/details_provide.dart';
import '../../model/details_model.entity.dart';
class DetailsCompany extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Provide<DetailsPageProvide>(
builder: (context,child,val){
var datas = val.datas;
return Container(
color: Colors.white,
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.only(top: 20.0),
child: Center(
child: Text(datas.wayChooseUs.subject),
),
),
_buildBrands(context, datas.wayChooseUs.titleTextImgs)
],
),
);
},
);
}
//圆形图片
Widget _buildBrands(BuildContext context,List<DetailsModelDatasWaychooseusTitletextimg> titleTextImgs){
return Padding(
padding: EdgeInsets.all(20.0),
child: Container(
child: Wrap(
spacing: 30.0,
runSpacing: 30.0,
children: _buildCompanyList(context, titleTextImgs),
),
),
);
}
List<Widget> _buildCompanyList(BuildContext context,List<DetailsModelDatasWaychooseusTitletextimg> titleTextImgs){
List<Widget> list = new List();
for(var i = 0; i < titleTextImgs.length; i++){
list.add(
Container(
width: (MediaQuery.of(context).size.width - 100.0)/3,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: ClipOval(
child: Image.network(titleTextImgs[i].image),
),
),
SizedBox(height: 2.0,),
Container(
alignment: Alignment.center,
child: Text(titleTextImgs[i].title),
)
],
),
)
);
}
return list;
}
}
熟能生巧,写多了,这种布局写起来就没什么难度了。
图文详情
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../../provide/details_provide.dart';
import '../../model/details_model.entity.dart';
class DetailsImgText extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Provide<DetailsPageProvide>(
builder: (context,child,val){
var datas = val.datas;
return Container(
color: Colors.white,
child: Column(
children: <Widget>[
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.all(15.0),
child: Text("图文详情"),
),
_buildImages(context, datas.itemImages)
],
)
);
},
);
}
//循环图片
Widget _buildImages(BuildContext context,List<String> itemImage){
List<Widget> lists = List();
for(var i = 0; i < itemImage.length; i++){
lists.add(
Container(
width: MediaQuery.of(context).size.width,
child: Image.network(itemImage[i],
fit: BoxFit.fitWidth,
),
)
);
}
return Column(
children: lists,
);
}
}
给图片选择一个填充方式: fit:BoxFit.fitWidth.
底部购物车栏
import 'package:flutter/material.dart';
class DetailsBottom extends StatelessWidget {
const DetailsBottom({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
var itemW = MediaQuery.of(context).size.width / 6;
return Container(
color: Colors.white,
width: MediaQuery.of(context).size.width,
height: 60.0,
child: Row(
children: <Widget>[
//客服
InkWell(
onTap: (){
print("点击了客服");
},
child: Container(
width: itemW,
decoration: BoxDecoration(
border: Border(
right: BorderSide(width: 1,color: Colors.black38)
)
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.phone_iphone,
color: Colors.black45,
size: 30.0,
),
Text("客服")
],
),
),
),
Container(
width: itemW,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.shopping_cart,
size: 30.0,
color: Colors.black45,
),
Text("购物车")
],
),
),
Container(
width: 2*itemW,
color: Color.fromRGBO(45, 60, 49, 1.0),
alignment: Alignment.center,
child: Text(
"加入购物车",
style:TextStyle(
color:Colors.white
)
),
),
Container(
width: 2*itemW,
color: Colors.orangeAccent,
alignment: Alignment.center,
child: Text(
"立即购买",
style:TextStyle(
color:Colors.white
)
),
)
],
),
);
}
}
这个主要就是在嵌入商品详情页的时候,是要悬浮在详情页其它组件之上且在底部:
Positioned(
bottom: 0,
left: 0,
child: DetailsBottom(),
)
商品详情页就这么多东西,然后其中的各种数据交互的逻辑都还没做,这个得和后面的购物车结合起来做。最后这个项目完成后代码会上传到gitHub上。 其次其中写得不好的请指正,共同进步。
下一篇购物车界面
网友评论