17.4 多选单选购物项&删除

17.4 多选单选购物项&删除

实现步骤:


第 1 步:CheckBox 选择框组件

image-20220728170407765

lib/common/widgets/checkbox.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import 'package:flutter/material.dart';

import '../index.dart';

/// CheckBox 选择框
class CheckBoxWidget extends StatelessWidget {
final bool value;
final Function(bool value)? onChanged;

/// 中间 icon
final Widget? icon;
final Widget? iconChecked;
final double? fontSize;
final Color? fontColor;

/// 大小
final double? size;

/// 外框
final Color? bgColor;
final Color? bgColorChecked;
final bool? isBorder;
final Color? borderColor;

/// 文本
final Widget? label;
final double? space;

CheckBoxWidget({
Key? key,
required this.value,
this.onChanged,
this.size = 20,
this.bgColor,
this.bgColorChecked,
this.fontSize = 14,
this.fontColor,
this.isBorder = true,
this.borderColor,
this.label,
this.space = 14,
this.icon,
Widget? iconChecked,
}) : iconChecked = iconChecked ??
IconWidget.icon(
Icons.check,
size: fontSize,
color: fontColor ?? AppColors.onPrimaryContainer,
),
super(key: key);

/// 样式1 - 全选
CheckBoxWidget.all(
this.value,
this.onChanged, {
Key? key,
Color? borderColor,
this.fontColor,
this.fontSize = 16,
this.size = 24,
this.bgColor,
this.bgColorChecked,
this.isBorder = true,
this.label,
double? space,
this.icon,
Widget? iconChecked,
}) : borderColor = borderColor ?? AppColors.outline,
space = space ?? AppSpace.iconTextSmail,
iconChecked = iconChecked ??
IconWidget.icon(
Icons.check,
size: fontSize,
color: fontColor ?? AppColors.onPrimaryContainer,
),
super(key: key);

/// 样式3 - 行选中
CheckBoxWidget.radio(
this.value,
this.onChanged, {
Key? key,
this.borderColor,
this.fontColor,
this.fontSize = 18,
this.size,
this.bgColor,
this.bgColorChecked,
this.isBorder = false,
this.label,
double? space,
Widget? icon,
Widget? iconChecked,
}) : icon = icon ??
IconWidget.icon(
Icons.radio_button_unchecked,
size: fontSize,
color: fontColor ?? AppColors.highlight,
),
iconChecked = iconChecked ??
IconWidget.icon(
Icons.radio_button_checked,
size: fontSize,
color: fontColor ?? AppColors.highlight,
),
space = space ?? AppSpace.iconTextSmail,
super(key: key);

/// 样式2 - 行选中 无边框
CheckBoxWidget.single(
this.value,
this.onChanged, {
Key? key,
this.borderColor,
this.fontColor,
this.fontSize = 14,
this.size = 20,
Color? bgColor,
Color? bgColorChecked,
this.isBorder = false,
this.label,
double? space,
this.icon,
Widget? iconChecked,
}) : iconChecked = iconChecked ??
IconWidget.icon(
Icons.check,
size: fontSize,
color: fontColor ?? AppColors.onPrimaryContainer,
),
space = space ?? AppSpace.iconTextSmail,
bgColor = bgColor ?? AppColors.surfaceVariant.withOpacity(0.3),
bgColorChecked = bgColorChecked ?? AppColors.primaryContainer,
super(key: key);

@override
Widget build(BuildContext context) {
var ws = <Widget>[];
ws.add(SizedBox(
width: size,
height: size,
child: value == true ? iconChecked : icon,
).decorated(
color: value == true ? bgColorChecked : bgColor,
border: isBorder == true
? Border.all(
color: borderColor ?? AppColors.outline,
width: 1,
)
: null,
borderRadius:
size != null ? BorderRadius.all(Radius.circular(size! / 2)) : null,
));

if (label != null) {
ws.add(label!.paddingLeft(space ?? AppSpace.iconTextSmail));
}

return GestureDetector(
onTap: onChanged != null ? () => onChanged!(!value) : null,
child: ws.toRow(),
);
}
}

lib/pages/styles/inputs/controller.dart

1
2
3
4
5
bool checkVal = true;
void onCheckBox(bool val) {
checkVal = val;
update(["inputs"]);
}

lib/pages/styles/inputs/view.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Widget _buildInputs() {
return <Widget>[
...

/// 选择框
CheckBoxWidget(
value: controller.checkVal,
onChanged: controller.onCheckBox,
).width(300).paddingBottom(AppSpace.listRow),

/// 选择框 all
CheckBoxWidget.all(
controller.checkVal,
controller.onCheckBox,
label: const TextWidget.title3("全选"),
).width(300).paddingBottom(AppSpace.listRow),

/// 选择框 single
CheckBoxWidget.single(
controller.checkVal,
controller.onCheckBox,
label: const TextWidget.title3("行选择"),
).width(300).paddingBottom(AppSpace.listRow),

/// 选择框 radio
CheckBoxWidget.radio(
controller.checkVal,
controller.onCheckBox,
label: const TextWidget.body1("radio"),
).width(300).paddingBottom(AppSpace.listRow),

第 2 步:控制器

lib/pages/cart/cart_index/controller.dart

1
2
3
4
5
// 优惠券代码
String couponCode = '';

// 商品是否选中
List<int> selectedIds = [];
1
2
3
4
5
// 是否全选
bool get isSelectedAll => CartService.to.lineItems.isEmpty
? false
: CartService.to.lineItems.length == selectedIds.length;

1
2
3
4
// 是否选中
bool isSelected(int productId) {
return selectedIds.any((val) => val == productId);
}
1
2
3
4
5
6
7
8
9
10
11
12
// 全选
void onSelectAll(bool isSelected) {
if (isSelected) {
// 全选
selectedIds =
CartService.to.lineItems.map((item) => item.productId!).toList();
} else {
// 全不选
selectedIds.clear();
}
update(["cart_index"]);
}
1
2
3
4
5
6
7
8
9
10
11
// 选中
void onSelect(int productId, bool isSelected) {
if (isSelected) {
// 全选
selectedIds.add(productId);
} else {
// 全不选
selectedIds.remove(productId);
}
update(["cart_index"]);
}
1
2
3
4
5
6
7
8
9
// 删除购物车订单
Future<void> onOrderCancel() async {
for (var i = 0; i < selectedIds.length; i++) {
int productId = selectedIds[i];
CartService.to.cancelOrder(productId);
}
selectedIds.clear();
update(["cart_index"]);
}

第 3 步:购物车列表项

lib/pages/cart/cart_index/widgets/cart_item.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/// 购物车列表项
class CartItem extends StatelessWidget {
/// 订单数据
final LineItem lineItem;

/// 是否全选
final bool isSelected;

/// 修改数量事件
final Function(int)? onChangeQuantity;

/// 选中事件
final Function(bool)? onSelect;

const CartItem({
Key? key,
required this.lineItem,
required this.isSelected,
this.onChangeQuantity,
this.onSelect,
}) : super(key: key);

// 主视图
Widget _buildView() {
// 商品
ProductModel product = lineItem.product!;

return <Widget>[
// 单选框
CheckBoxWidget.all(
isSelected,
onSelect,
fontColor: AppColors.primary,
bgColorChecked: AppColors.primaryContainer,
size: 20.sp,
).paddingRight(AppSpace.iconTextSmail),

加入 isSelected ,单选框组件

第 3 步:顶部多选栏 lib/pages/cart/cart_index/widgets/action_bar.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import 'package:flutter/cupertino.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_woo_commerce_getx_learn/common/index.dart';
import 'package:get/get.dart';

/// 顶部操作栏
class ActionBar extends StatelessWidget {
final bool isAll;
final Function(bool)? onAll;
final Function()? onRemove;

const ActionBar({
Key? key,
this.onAll,
this.isAll = false,
this.onRemove,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return <Widget>[
// 选择框
CheckBoxWidget.all(
isAll,
onAll,
size: 24.sp,
fontColor: AppColors.highlight,
label: TextWidget.body1(
LocaleKeys.gCartBtnSelectAll.tr,
),
).expanded(),

// 删除按钮
ButtonWidget.icon(
IconWidget.icon(
CupertinoIcons.delete,
size: 20.sp,
),
onTap: onRemove,
),
].toRow();
}
}

第 3 步:商品项单选

lib/pages/cart/cart_index/view.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 订单列表
Widget _buildOrders() {
return ListView.separated(
itemBuilder: (BuildContext context, int index) {
LineItem item = CartService.to.lineItems[index];
return CartItem(
lineItem: item,
// 是否选中
isSelected: controller.isSelected(item.productId!),
// 选中回调
onSelect: (isSelected) =>
controller.onSelect(item.productId!, isSelected),
).paddingAll(AppSpace.card).card();
},
separatorBuilder: (BuildContext context, int index) {
return SizedBox(height: AppSpace.listRow);
},
itemCount: CartService.to.lineItems.length,
);
}

isSelected onSelect 事件分别响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Widget _buildView() {
return <Widget>[
// 顶部操作栏
ActionBar(
onAll: controller.onSelectAll,
onRemove: controller.onOrderCancel,
isAll: controller.isSelectedAll,
).paddingAll(AppSpace.page),

// 订单列表
_buildOrders().paddingHorizontal(AppSpace.page).expanded(),

// 优惠券
_buildCoupons().paddingAll(AppSpace.page),

// 费用小计
_buildTotal(),
].toColumn();
}

提交代码到 git