12.1 商品界面初始

12.1 商品界面初始

image-20220722141129756

实现步骤:


第 1 步:i18n

1
2
3
4
5
6
7
// 商品 - 详情
static const gDetailTitle = "goods_detail_title";
static const gDetailTabProduct = "goods_detail_tab_product";
static const gDetailTabDetails = "goods_detail_tab_details";
static const gDetailTabReviews = "goods_detail_tab_reviews";
static const gDetailBtnAddCart = "goods_detail_btn_add_cart";
static const gDetailBtnBuy = "goods_detail_btn_buy";

lib/common/i18n/locales/locale_en.dart

1
2
3
4
5
6
7
// 商品 - 详情
LocaleKeys.gDetailTitle: 'Product Info',
LocaleKeys.gDetailTabProduct: 'Product',
LocaleKeys.gDetailTabDetails: 'Details',
LocaleKeys.gDetailTabReviews: 'Reviews',
LocaleKeys.gDetailBtnAddCart: 'Add To Cart',
LocaleKeys.gDetailBtnBuy: 'Buy Now',

lib/common/i18n/locales/locale_zh.dart

1
2
3
4
5
6
7
// 商品 - 详情
LocaleKeys.gDetailTitle: '商品信息',
LocaleKeys.gDetailTabProduct: '规格',
LocaleKeys.gDetailTabDetails: '说明',
LocaleKeys.gDetailTabReviews: '评论',
LocaleKeys.gDetailBtnAddCart: '加入购物车',
LocaleKeys.gDetailBtnBuy: '立刻购买',

第 2 步:Stateful + GetX 结构

goods 目录右键菜单创建

image-20220722060209736

默认状态保持开启 wantKeepAlive => true

lib/pages/goods/product_details/controller.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
/// 商品详情页
class ProductDetailsPage extends StatefulWidget {
const ProductDetailsPage({Key? key}) : super(key: key);

@override
State<ProductDetailsPage> createState() => _ProductDetailsPageState();
}

class _ProductDetailsPageState extends State<ProductDetailsPage>
with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;

第 3 步:tag 区分商品页

lib/pages/goods/product_details/view.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class _ProductDetailsGetx extends GetView<ProductDetailsController> {
// 1 定义唯一 tag 变量
final String uniqueTag;

// 2 接收传入 tag 值
const _ProductDetailsGetx(this.uniqueTag, {Key? key}) : super(key: key);

// 3 重写 GetView 属性 tag
@override
String? get tag => uniqueTag;

...

@override
Widget build(BuildContext context) {
return GetBuilder<ProductDetailsController>(
init: ProductDetailsController(),
id: "product_details",
// 4 GetBuilder 属性 tag 设置
tag: tag,
builder: (_) {

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class _ProductDetailsPageState extends State<ProductDetailsPage>
with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;

// 5 定义 tag 值,唯一即可
final String tag = '${Get.arguments['id'] ?? ''}${UniqueKey()}';

@override
Widget build(BuildContext context) {
super.build(context);

// 6 实例传入 tag
return _ProductDetailsGetx(tag);
}
}

通过 tag 属性 进行区分不同商品控制器 Controller

第 4 步:子组件

商品规格

lib/pages/goods/product_details/widgets/tab_product.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import 'package:flutter/material.dart';
import 'package:get/get.dart';

import '../index.dart';

/// 商品规格
class TabProductView extends GetView<ProductDetailsController> {
final String uniqueTag;

const TabProductView({Key? key, required this.uniqueTag}) : super(key: key);

@override
String? get tag => uniqueTag;

@override
Widget build(BuildContext context) {
return const Text("商品规格");
}
}

商品详情

lib/pages/goods/product_details/widgets/tab_detail.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import 'package:flutter/material.dart';
import 'package:get/get.dart';

import '../index.dart';

/// 商品详情
class TabDetailView extends GetView<ProductDetailsController> {
final String uniqueTag;

const TabDetailView({Key? key, required this.uniqueTag}) : super(key: key);

@override
String? get tag => uniqueTag;

@override
Widget build(BuildContext context) {
return const Text("商品详情");
}
}

商品评论

lib/pages/goods/product_details/widgets/tab_reviews.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import 'package:flutter/material.dart';
import 'package:get/get.dart';

import '../index.dart';

/// 评论
class TabReviewsView extends GetView<ProductDetailsController> {
final String uniqueTag;

const TabReviewsView({Key? key, required this.uniqueTag}) : super(key: key);

@override
String? get tag => uniqueTag;

@override
Widget build(BuildContext context) {
return const Text("评论");
}
}

第 5 步:视图

lib/pages/goods/product_details/view.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 滚动图
Widget _buildBanner() {
return Text("滚动图");
}

// 商品标题
Widget _buildTitle() {
return Text("滚动图");
}

// Tab 栏位
Widget _buildTabBar() {
return Text("Tab 栏位");
}

// TabView 视图
Widget _buildTabView() {
return Text("TabView 视图");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 主视图
Widget _buildView() {
return <Widget>[
// 滚动图
_buildBanner(),

// 商品标题
_buildTitle(),

// Tab 栏位
_buildTabBar(),

// TabView 视图
_buildTabView(),
].toColumn();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@override
Widget build(BuildContext context) {
return GetBuilder<ProductDetailsController>(
init: ProductDetailsController(),
id: "product_details",
// 4 GetBuilder 属性 tag 设置
tag: tag,
builder: (_) {
return Scaffold(
// 导航
appBar: mainAppBarWidget(
titleString:LocaleKeys.gDetailTitle.tr),
// 内容
body: SafeArea(
child: _buildView(),
),
);
},
);
}

提交代码到 git