基础工程:
Flutter系列(四)底部导航+顶部导航+图文列表完整代码_摸金青年v的博客-CSDN博客
一、前言
本文用flutter实现商城首页和商品详情页,效果如下图:
二、使用的组件
MasonryGridView.count 瀑布流插件,组合Expanded可以添加固定在底部的按钮组
三、完整代码
3.1 商城首页
1)瀑布流官方插件文档:flutter_staggered_grid_view | Flutter Package (pub.dev)
pubspec.yaml 添加依赖:
dependencies:
flutter:
sdk: flutter
# 瀑布流插件
flutter_staggered_grid_view: ^0.6.2
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
2)页面跳转动画特效:动画特效工具类 animationUtile.dart
参考文章:Flutter系列(九)ListView实现新闻列表和正文布局_摸金青年v的博客-CSDN博客
3)顶部搜索框
参考文章:Flutter系列(八)搜索框详解_flutter 搜索框_摸金青年v的博客-CSDN博客
商城首页 shop.dart
import 'package:flutter/material.dart';
import 'package:flutter_play/search.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter_play/animationUtile.dart';
import 'package:flutter_play/skuDetail.dart';
/*商城页*/
class ShopPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: const Color(0xFFFBFBFB), //顶部背景色
title: SearchAppBar(), // 顶部搜素框(自定义组件)
),
body: Column(
children: [
Container(
margin: const EdgeInsets.all(8),
width: 500,
height: 180,
child: Image.network('https://img-blog.csdnimg.cn/63efe7acbac74e7ebce85e3801f948e3.jpeg'
, fit: BoxFit.fill, width: 500, height: 200), //可放轮播图 商品类别 筛选之类的
),
Expanded(
child: MasonryGridView.count( //瀑布流插件
itemCount: listData.length, //条目个数:获取数据的个数
scrollDirection: Axis.vertical, //默认主轴是垂直方向
crossAxisCount: 2, //交叉轴(水平方向)列数
mainAxisSpacing: 4, //主轴:垂直方向间距
crossAxisSpacing: 4, //交叉轴:水平方向间距
itemBuilder: _showSku,
// shrinkWrap:true, //含义是真空压缩组件,对性能损耗很大,不建议使用
), //Expanded 解决GridView嵌套在Column中不兼容的问题
)
]
),
);
}
//sku列表展示
Widget _showSku(context, index) {
return Container(
padding: const EdgeInsets.fromLTRB(8, 5, 8, 5),
decoration: BoxDecoration(
border: Border.all(
color: const Color.fromRGBO(233, 233, 233, 0.9), //边框颜色
width: 2, //边框宽度
), //边框
),
child: GestureDetector(
onTap: () {
Navigator.of(context).push(showPageFromRight(SkuDetailPage())); //点击跳转到商品详情页
},
child: Column(
children: [
Image.network(listData[index]["imageUrl"],
height: 150,
width: double.infinity, //宽度撑满
fit: BoxFit.cover //图片撑满父容器,截断
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceAround, //沿着主轴方向(垂直方向)间距等分
crossAxisAlignment: CrossAxisAlignment.start, //水平方向左侧对齐
children: [
Text(listData[index]["title"], style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w600),
maxLines: 2, //最大显示两行
overflow: TextOverflow.ellipsis //超出部分省略号
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, //水平方向两端对齐
children: [
Row(
children: [
const Text(' ¥', style: TextStyle(color: Colors.redAccent, fontSize: 12, fontWeight: FontWeight.w600)),
Text(listData[index]["price"], style: const TextStyle(color: Colors.redAccent, fontSize: 12, fontWeight: FontWeight.w600)),
],
),
Row(
children: [
const Text('销量 ', style: TextStyle(color: Colors.grey, fontSize: 12, fontWeight: FontWeight.w600)),
Text(listData[index]["saleNum"], style: const TextStyle(color: Colors.grey, fontSize: 12, fontWeight: FontWeight.w600)), //数据类型要准确,Text必须是String
],
),
],
),
]
)
],
),
)
);
}
//数据
List listData = [
{
"title": "OPPO K9x 8GB+128GB 银紫超梦 天玑810 5000mAh长续航 33W快充 90Hz电竞",
"price": "2788",
"imageUrl": "https://img-blog.csdnimg.cn/c6dfd375abf1433fa3a42951cc186a2b.jpeg",
"saleNum": "3000"
},
{
"title": "Redmi K60 骁龙8+处理器 2K高光屏 6400万超清相机 5500mAh长续航",
"price": "2998",
"imageUrl": "https://img-blog.csdnimg.cn/c6dfd375abf1433fa3a42951cc186a2b.jpeg",
"saleNum": "500"
},
{
"title": "Apple iPhone 14 Pro (A2892) 256GB 暗紫色 支持移动联通电信5G 双卡双待手机",
"price": "5899",
"imageUrl": "https://img-blog.csdnimg.cn/c6dfd375abf1433fa3a42951cc186a2b.jpeg",
"saleNum": "2400"
},
{
"title": "三星 SAMSUNG Galaxy Z Fold4 沉浸大屏体验 PC般强大生产力 12GB+512GB",
"price": "4677",
"imageUrl": "https://img-blog.csdnimg.cn/c6dfd375abf1433fa3a42951cc186a2b.jpeg",
"saleNum": "600"
},
{
"title": "华为畅享 60X 7000mAh长续航 6.95英寸 影音大屏 256GB 曜金黑 鸿蒙智能手机",
"price": "3778",
"imageUrl": "https://img-blog.csdnimg.cn/c6dfd375abf1433fa3a42951cc186a2b.jpeg",
"saleNum": "900"
},
{
"title": "荣耀X30 骁龙6nm疾速5G芯 66W超级快充 120Hz全视屏 全网通版",
"price": "4999",
"imageUrl": "https://img-blog.csdnimg.cn/c6dfd375abf1433fa3a42951cc186a2b.jpeg",
"saleNum": "500"
},
{
"title": "Apple iPhone 14 Pro (A2892) 256GB 暗紫色 支持移动联通电信5G 双卡双待手机",
"price": "5899",
"imageUrl": "https://img-blog.csdnimg.cn/c6dfd375abf1433fa3a42951cc186a2b.jpeg",
"saleNum": "300"
},
{
"title": "三星 SAMSUNG Galaxy Z Fold4 沉浸大屏体验 PC般强大生产力 12GB+512GB",
"price": "4677",
"imageUrl": "https://img-blog.csdnimg.cn/c6dfd375abf1433fa3a42951cc186a2b.jpeg",
"saleNum": "100"
}
];
}
3.2 商品详情页
import 'package:flutter/material.dart';
import 'package:flutter_play/animationUtile.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter_play/cart.dart';
/*商品详情页*/
class SkuDetailPage extends StatefulWidget {
@override
State<SkuDetailPage> createState() => _SkuDetailPage();
}
class _SkuDetailPage extends State<SkuDetailPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
foregroundColor: Colors.black, //字体颜色
backgroundColor: const Color(0xFFFBFBFB), //顶部背景色
title: const Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text('商品', style: TextStyle(fontWeight: FontWeight.w500, fontSize: 15)),
Text('评价', style: TextStyle(fontWeight: FontWeight.w500, fontSize: 15)),
Text('详情', style: TextStyle(fontWeight: FontWeight.w500, fontSize: 15)),
Text('推荐', style: TextStyle(fontWeight: FontWeight.w500, fontSize: 15)),
],
),
actions: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.share),
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.more_horiz),
),
],
),
body: Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
Image.network('https://img-blog.csdnimg.cn/c6dfd375abf1433fa3a42951cc186a2b.jpeg', fit: BoxFit.fill, width: 500, height: 260), // 图片
priceInfo(), // 价格和促销
skuInfo(), // 商品参数
comment(), // 评价
],
),
),
),
bottomFix() //底部固定栏
],
)
);
}
/*价格信息*/
Container priceInfo(){
return Container(
width: 500,
height: 45,
decoration: BoxDecoration(
color: const Color.fromARGB(50, 255, 48, 48),
borderRadius: BorderRadius.circular(6), // 设置圆角
),
margin: const EdgeInsets.all(5),
padding: const EdgeInsets.all(5),
child: const Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('到手价 ¥4999', style: TextStyle(color: Colors.redAccent, fontSize: 14, fontWeight: FontWeight.w600)),
Text('立减20 | 30天价保 | 包含运费险', style: TextStyle(color: Colors.redAccent, fontSize: 12, fontWeight: FontWeight.w400)),
],
),
);
}
/*商品名称+选品+地址+时效*/
Container skuInfo(){
return Container(
width: 500,
height: 200,
margin: const EdgeInsets.all(5),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: const Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text('Apple iPhone 14 Pro (A2892) 256GB 暗紫色 支持移动联通电信5G 双卡双待手机', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600)), //商品名称
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, //水平方向两端对齐
children: [
Text('选品 ', style: TextStyle(color: Colors.grey, fontSize: 14, fontWeight: FontWeight.w400)),
Text('已选: 暗紫色 1件 256G 0.33kg', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400)),
Icon(Icons.arrow_forward_ios, size: 10)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, //水平方向两端对齐
children: [
Text('参数 ', style: TextStyle(color: Colors.grey, fontSize: 14, fontWeight: FontWeight.w400)),
Column(
children: [
Text('A15 ', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400)),
Text('cpu ', style: TextStyle(color: Colors.grey, fontSize: 14, fontWeight: FontWeight.w400)),
],
),
Column(
children: [
Text('6.1英寸 ', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400)),
Text('尺寸 ', style: TextStyle(color: Colors.grey, fontSize: 14, fontWeight: FontWeight.w400)),
],
),
Column(
children: [
Text('OLED直屏 ', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400)),
Text('屏幕材质 ', style: TextStyle(color: Colors.grey, fontSize: 14, fontWeight: FontWeight.w400)),
],
),
Icon(Icons.arrow_forward_ios, size: 10)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, //水平方向两端对齐
children: [
Text('配送 ', style: TextStyle(color: Colors.grey, fontSize: 14, fontWeight: FontWeight.w400)),
Column(
children: [
Text('北京 海淀区', style: TextStyle(color: Colors.grey, fontSize: 14, fontWeight: FontWeight.w400)),
Text('现货,预计今天(06月23日)送达', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400)),
],
),
Icon(Icons.arrow_forward_ios, size: 10)
],
)
],
),
);
}
/*评价*/
Container comment(){
return Container(
width: 500,
height: 190,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10), // 设置圆角
),
margin: const EdgeInsets.all(10),
padding: const EdgeInsets.only(top: 5),
// alignment: Alignment.centerLeft,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
const Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, //水平方向两端对齐
children: [
Text('评价 (200万+)', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400)),
Row(
children: [
Text('好评度 97%', style: TextStyle(color: Colors.grey, fontSize: 12, fontWeight: FontWeight.w400)),
Icon(Icons.arrow_forward_ios, size: 10)
],
),
],
),
SizedBox(height: 2),
Row(
children: [
ClipOval(
child: Image.network('https://img-blog.csdnimg.cn/c6dfd375abf1433fa3a42951cc186a2b.jpeg', width: 30, height: 30, fit: BoxFit.cover),
), //圆型头像
const Text(' 吴邪', style: TextStyle(color: Colors.grey, fontSize: 14, fontWeight: FontWeight.w400)),
],
),
SizedBox(height: 2),
const Text('外观: 小巧精致,手感不错,屏幕流畅,拍照功能强大', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400)),
SizedBox(height: 3),
Expanded(
child: MasonryGridView.count(
scrollDirection: Axis.horizontal, //水平方向
itemCount: listData.length, //条目个数:获取数据的个数
crossAxisCount: 1, //交叉轴(水平方向)行数
mainAxisSpacing: 4,
crossAxisSpacing: 4,
itemBuilder: (context, index) {
return Image.network(listData[index]["imageUrl"], width: 120, height: 50, fit: BoxFit.cover);
}
),
)//图片组
],
),
);
}
List listData = [
{
"imageUrl": "https://img-blog.csdnimg.cn/c6dfd375abf1433fa3a42951cc186a2b.jpeg",
},
{
"imageUrl": "https://img-blog.csdnimg.cn/c6dfd375abf1433fa3a42951cc186a2b.jpeg",
},
{
"imageUrl": "https://img-blog.csdnimg.cn/c6dfd375abf1433fa3a42951cc186a2b.jpeg",
},
{
"imageUrl": "https://img-blog.csdnimg.cn/c6dfd375abf1433fa3a42951cc186a2b.jpeg",
},
{
"imageUrl": "https://img-blog.csdnimg.cn/c6dfd375abf1433fa3a42951cc186a2b.jpeg",
}
];
/*底部固定:购物车+立即购买*/
Container bottomFix(){
return Container(
width: 500,
height: 50,
color: Colors.white,
// alignment: Alignment.centerLeft,
child: ButtonBar(
children: [
IconButton(
color: Colors.grey,
icon: const Icon(Icons.add_business), //店铺
onPressed:(){},
),
IconButton(
color: Colors.grey,
icon: const Icon(Icons.star_border_outlined), //收藏
onPressed:(){},
),
IconButton(
color: Colors.grey,
icon: const Icon(Icons.add_shopping_cart), //购物车
onPressed:(){
Navigator.of(context).push(showPageFromRight(CartPage())); //点击购物车图标,进入购物车页
},
),
TextButton (
style: ButtonStyle(
minimumSize: MaterialStateProperty.all(const Size(80, 50)),
foregroundColor: MaterialStateProperty.all<Color>(Colors.pinkAccent), //字体颜色
shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))), //圆角
side: MaterialStateProperty.all(const BorderSide(color: Colors.pinkAccent, width: 0.67)) // 边框颜色
),
child: const Text('加入购物车'),
onPressed: () {
},
),
TextButton (
style: ButtonStyle(
minimumSize: MaterialStateProperty.all(const Size(80, 50)),
backgroundColor: MaterialStateProperty.all(Colors.pinkAccent),
foregroundColor: MaterialStateProperty.all<Color>(Colors.white), //字体颜色
shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))) //圆角
),
child: const Text('立即购买'),
onPressed: () {
},
),
]
),
);
}
}
四、解决问题
4.1 商品详情页-评论模块的,图片组支持水平滑动,使用的还是瀑布流组件,需要设置参数:
1.设置了水平方向为主轴,表示滚动方向为水平
2.设置了交叉轴行数等于1,表示图片只有一行显示
MasonryGridView.count(
scrollDirection: Axis.horizontal, //水平方向
itemCount: listData.length, //条目个数:获取数据的个数
crossAxisCount: 1, //交叉轴(水平方向)行数
mainAxisSpacing: 4,
crossAxisSpacing: 4,
itemBuilder: (context, index) {
return Image.network(listData[index]["imageUrl"], width: 120, height: 50, fit: BoxFit.cover);
}
),
本文结束