一、表单封装组件实现效果
//表单组件
Widget buildFormWidget(List<InputModel> formList,
{required GlobalKey<FormState> formKey}) {
return Form(
key: formKey,
child: Column(
children: formList.map((item) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
item.isRequired
? Icon(Icons.star,
size: 10,
color: Theme.of(Get.context!).colorScheme.error)
: SizedBox(),
Text(
item.label,
style:
Theme.of(Get.context!).inputDecorationTheme.labelStyle,
)
],
),
SizedBox(
height: 16,
),
GestureDetector(
onTap: item.type == 'select'
? () {
showBottomSheet(item.bottomSheetList!, item.label,
selectProp: item.selectProp,
selectController: item.selectController,
controller: item.controller);
}
: null,
child: TextFormField(
controller: item.controller,
enabled: item.type == 'text',
keyboardType: item.keyboardType,
validator: (value) {
// 添加表单验证
if (item.isRequired && (value == null || value.isEmpty)) {
return '请${item.type == 'select' ? '选择' : '输入'}${item.label}';
}
//正则表达式验证
if (item.pattern.isEmpty &&
(value == null || value.isEmpty)) {
RegExp regex = RegExp(item.pattern);
if (!regex.hasMatch(value!)) {
return '请输入正确的${item.label}';
}
}
return null;
},
decoration: InputDecoration(
suffixIcon: item.type == 'select'
? Icon(Icons.arrow_forward_ios,
color: Color(0x6615171E))
: null,
focusedBorder: Theme.of(Get.context!)
.inputDecorationTheme
.focusedBorder,
disabledBorder: Theme.of(Get.context!)
.inputDecorationTheme
.disabledBorder,
enabledBorder: Theme.of(Get.context!)
.inputDecorationTheme
.enabledBorder,
errorBorder:
Theme.of(Get.context!).inputDecorationTheme.errorBorder,
errorStyle:
Theme.of(Get.context!).inputDecorationTheme.errorStyle,
hintText:
'请${item.type == 'select' ? '选择' : '输入'}${item.label}',
isDense: true,
filled: true,
fillColor:
Theme.of(Get.context!).inputDecorationTheme.fillColor,
),
),
),
SizedBox(
height: 16,
),
],
);
}).toList(),
));
}
//bottomSheet
void showBottomSheet(List<Map<String, dynamic>> list, String title,
{Map? selectProp,
RxMap<String, dynamic>? selectController,
TextEditingController? controller}) {
showGenderPanel(
title,
buildCheckList(list, (item) {
controller?.text = item[selectProp?['label']];
Get.back();
}, props: selectProp, selected: selectController));
}
// 底部弹出层
void showGenderPanel(String title, Widget sheetContent) {
showModalBottomSheet(
context: Get.context!,
builder: (context) {
return Container(
height: 800,
child: Column(
children: [
Container(
// height: 100,
padding: Theme.of(Get.context!).dialogTheme.actionsPadding,
child: Stack(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
title,
overflow: TextOverflow.ellipsis, // 显示省略号
style: Theme.of(Get.context!)
.dialogTheme
.titleTextStyle,
),
],
),
Positioned(
right: 20,
// top: 14,
child: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.cancel_outlined,
color: Theme.of(Get.context!)
.dialogTheme
.iconColor),
),
),
],
)),
Divider(
height: 1,
// color: Theme.of(Get.context!).dividerColor,
),
Container(
// padding: EdgeInsets.all(16),
child: sheetContent,
)
],
));
});
}
//单选列表
Widget buildCheckList(List<Map<String, dynamic>> list, Function? onChanged,
{Map? props, RxMap<String, dynamic>? selected}) {
props ??= {'label': 'label', 'value': 'value'};
String label = props['label'] ?? 'label';
String value = props['value'] ?? 'value';
return Obx(() => Container(
width: Get.width,
child: Column(
children: list.asMap().entries.map((entry) {
int index = entry.key;
dynamic item = entry.value;
print('渲染');
return Column(
children: [
GestureDetector(
onTap: () {
selected?.value = item;
if (onChanged != null) {
onChanged(item);
}
},
child: Container(
width: Get.width,
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0),
),
padding: const EdgeInsets.symmetric(
vertical: 16, horizontal: 16),
child: Row(
children: [
Icon(
(selected?.value[value] ?? '') == item[value]
? Icons.check_circle
: Icons.circle_outlined,
size: 22,
color: (selected?.value[value] ?? '') == item[value]
? Color.fromRGBO(50, 73, 223, 1)
: Color.fromRGBO(21, 23, 30, 0.40)),
SizedBox(width: 6),
Text(
item[label],
style: TextStyle(
fontSize: 16,
),
),
],
),
)),
Divider(
height: 1,
color: index + 1 == list.length
? Color.fromRGBO(128, 130, 145, 0)
: Color.fromRGBO(128, 130, 145, 0.20),
),
],
);
}).toList(),
)));
}
二、调用方法:
buildFormWidget(formList, formKey: formKey),
三、数据格式:
Map<String, dynamic> controllers = {
'phone': TextEditingController(text: '仓库1'),
'phoneSelect': <String, dynamic>{'id': '18', 'name': '仓库1'}.obs,
'code': TextEditingController(text: '123'),
};
formList = [
InputModel(
label: '入库仓库',
isRequired: true,
type: 'select',
controller: controllers['phone'],
selectController: controllers['phoneSelect'],
bottomSheetList: bottomSheetList,
selectProp: {'label': 'name', 'value': 'id'}),
InputModel(
label: '入库数量',
isRequired: true,
keyboardType: TextInputType.number,
controller: controllers['code']),
];