# ecp_dform_app **Repository Path**: kitman/ecp_dform_app ## Basic Information - **Project Name**: ecp_dform_app - **Description**: No description available - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-25 - **Last Updated**: 2026-10-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ecp_dform_app ecp_dform_app 是一个自动生成渲染表单组件的组件库,通过渲染特定规则Json字符串渲染样式,特定规则数据Json字符串渲染数据;目前组件支持渲染如下组件: > 此库专为内部项目需求设计,若不符合您的使用场景,敬请谅解。 - 输入框(Input) - 数字输入框(InputNumber) - 多行输入框 (Input.TextArea) - 备注(remark) - 时间选择 (TimePicker) - 日期选择 (DatePicker) - 组件布局(FormLayout) - 单选框 (Radio.Group) - 组件网格布局(FormGrid) - 组件网格子布局 (FormGrid.GridColumn) - 上传文件 (YiFileUpload) 对应默认组件名称如下: - input/InputNumber ->TextEditorField - datePicker ->DatePickerField - timePicker ->TimePickerField - textArea/textArea ->TextAreaField - radioGroup ->radioPicker - formGrid ->formGrid - gridColumn ->gridColumn - fileUpload -> UploadFileField ## 简单使用 - 准备组件样式Json字符串(本地或远程网络) ```json { "schema": { "x-designable-id": "momamuigso7", "type": "object", "properties": { "Input1": { "x-component": "Input", "x-decorator": "FormItem", "x-designable-id": "q5wn6s6b8a0", "x-display": "visible", "x-decorator-props": {}, "name": "Input1", "x-pattern": "readOnly", "x-validator": {}, "x-component-props": { "required": false }, "type": "string", "title": "输入1", "x-index": 0 }, "Input2": { "x-component": "Input", "x-decorator": "FormItem", "x-designable-id": "cse7oco9skb", "x-display": "visible", "x-decorator-props": { }, "name": "Input2", "x-pattern": "editable", "x-validator": { }, "x-component-props": { "required": true }, "type": "string", "title": "输入2", "x-index": 1 }, "ewgsrvgtu25": { "x-component": "Input", "x-decorator": "FormItem", "x-designable-id": "ewgsrvgtu25", "x-display": "visible", "x-decorator-props": {}, "x-pattern": "readOnly", "x-validator": {}, "x-component-props": { "required": true }, "type": "string", "title": "输入3", "x-index": 2 } } } } ``` - 准备对应组件初始化数据(本地或远程网络) ```json { "Input1": "3131", "Input2": "1414", "ewgsrvgtu25": "414141" } ``` - 渲染 ```dart DynamicForm( jsonSchema: _jsonSchema, ///样式Json字符串 dataSchema: _data, ///数据Json字符串 controller: controller, ///控制器 ) ``` ## 属性说明 ### DynamicForm 最终动态表单渲染组件,负责解析和渲染工作,默认渲染样式为ListView,其中包含可传入参数如下: - items:静态表单数据,内部包含组件样式及数据,适用于静态渲染 - controller:动态表单组件控制器,负责处理数据 - factory:组件样式适配器,默认为DefaultMapperFactory - jsonSchema:组件样式Json字符串 - dataSchema:组件数据字符串 - parse:解析器,负责将jsonSchema以及dataSchema解析为List - physics:滑动类型,因为表单可能内嵌于其他滑动组件,防止动态表单渲染组件内ListView与外部组件冲突,建议设置成NeverScrollableScrollPhysics - shrinkWrap:防止滑动嵌套时,内部ListView组件渲染不全 - permissions:控制表单组件显示、隐藏以及编辑功能 ### DynamicFormController 动态表单控制器,用来控制整体表单数据行为,提供如下方法: - reset:重置所有表单值 - save:保存当前表单值 - validate:校验表单组件是否合法 - submit:提交表单信息,首先通过[validate]方法校验是否表单是否合法,其次调用[save]方法保存表单数据至[FormSharedWidget]的[savedResult]中,最后调用[DynamicForm]的onSaved方法 ### DynamicFormConfig DynamicFormConfig保存了动态表单全局表单适配器以及解析器信息,可在应用初始化时替换 - factory:表单适配器,默认DefaultMapperFactory - parse:表单解析器,默认_defaultParse ## 默认表单组件 动态表单内设置了默认表单组件,可根据需求继承/重写表单样式。 ### TextEditorField ### ![Screenshot_20221124-110337.png](https://cdn.nlark.com/yuque/0/2022/png/2940130/1669259030949-1acdd8ae-9aaa-458e-b082-8fcf03e87994.png#averageHue=%23f7f8d6&clientId=uffbcbc01-ea1c-4&crop=0&crop=0&crop=1&crop=1&from=drop&height=678&id=u808f2452&margin=%5Bobject%20Object%5D&name=Screenshot_20221124-110337.png&originHeight=1440&originWidth=720&originalType=binary&ratio=1&rotation=0&showTitle=true&size=103343&status=done&style=shadow&taskId=ufea32806-b1fb-4b6e-98fd-52e366fae59&title=TextInput&width=339 "TextInput") ### TextPickField ![Screenshot_20221124-110542.png](https://cdn.nlark.com/yuque/0/2022/png/2940130/1669259152819-9592de65-593f-4b76-8f90-7ce49d5c9b1c.png#averageHue=%23a8a8a9&clientId=uffbcbc01-ea1c-4&crop=0&crop=0&crop=1&crop=1&from=drop&height=682&id=u1e4fa50d&margin=%5Bobject%20Object%5D&name=Screenshot_20221124-110542.png&originHeight=1440&originWidth=720&originalType=binary&ratio=1&rotation=0&showTitle=true&size=50527&status=done&style=shadow&taskId=u1ffa2eda-486b-494f-b24a-a4da904f264&title=TextPicker&width=341 "TextPicker") ### RadioPickerField ![Screenshot_20221124-110814.png](https://cdn.nlark.com/yuque/0/2022/png/2940130/1669259324964-439e89c2-8ec2-41fa-b9d1-972a07656fbd.png#averageHue=%23848587&clientId=uffbcbc01-ea1c-4&crop=0&crop=0&crop=1&crop=1&from=drop&height=696&id=ua47fe64e&margin=%5Bobject%20Object%5D&name=Screenshot_20221124-110814.png&originHeight=1440&originWidth=720&originalType=binary&ratio=1&rotation=0&showTitle=true&size=59606&status=done&style=shadow&taskId=u3d574c98-406c-4103-a177-fee7799775d&title=RadioPicker&width=348 "RadioPicker") ### DatePickerField ![Screenshot_20221124-110819.png](https://cdn.nlark.com/yuque/0/2022/png/2940130/1669259354388-9cc58c84-29ba-4c50-af42-de296a807b2a.png#averageHue=%237e8085&clientId=uffbcbc01-ea1c-4&crop=0&crop=0&crop=1&crop=1&from=drop&height=652&id=u491aeb7b&margin=%5Bobject%20Object%5D&name=Screenshot_20221124-110819.png&originHeight=1440&originWidth=720&originalType=binary&ratio=1&rotation=0&showTitle=true&size=70597&status=done&style=shadow&taskId=u3e0bae2e-973f-4953-b4c1-57cbe285022&title=DatePicker&width=326 "DatePicker") ### TimePickerField ![Screenshot_20221124-110824.png](https://cdn.nlark.com/yuque/0/2022/png/2940130/1669259416190-eeba9e29-ba1f-4a80-9fdd-4ab4c6e13b0f.png#averageHue=%23848587&clientId=uffbcbc01-ea1c-4&crop=0&crop=0&crop=1&crop=1&from=drop&height=664&id=u1ab702a5&margin=%5Bobject%20Object%5D&name=Screenshot_20221124-110824.png&originHeight=1440&originWidth=720&originalType=binary&ratio=1&rotation=0&showTitle=true&size=54531&status=done&style=shadow&taskId=u6c8af096-6c7a-4be9-958e-4918bb6de35&title=TimePicker&width=332 "TimePicker") ### UploadFileField(Card) ![Screenshot_20221124-112109.png](https://cdn.nlark.com/yuque/0/2022/png/2940130/1669260104456-ae6f236a-caf8-409e-999b-ff8c60c20c5f.png#averageHue=%2375782b&clientId=uffbcbc01-ea1c-4&crop=0&crop=0.5402&crop=0.9971&crop=0.8524&from=drop&height=696&id=u55c5b41d&margin=%5Bobject%20Object%5D&name=Screenshot_20221124-112109.png&originHeight=1440&originWidth=720&originalType=binary&ratio=1&rotation=0&showTitle=false&size=113925&status=done&style=stroke&taskId=u321b12e0-b4f1-4771-b791-c52486e6f9f&title=&width=348) ### **UploadFileField(List)** ### ![Screenshot_20221124-112116.png](https://cdn.nlark.com/yuque/0/2022/png/2940130/1669260232376-5bbecdf2-4d38-4dcf-92c5-ccbc8589d74d.png#averageHue=%23877922&clientId=uffbcbc01-ea1c-4&crop=0&crop=0.3154&crop=1&crop=0.7703&from=drop&height=672&id=u14e1ff79&margin=%5Bobject%20Object%5D&name=Screenshot_20221124-112116.png&originHeight=1440&originWidth=720&originalType=binary&ratio=1&rotation=0&showTitle=false&size=116098&status=done&style=stroke&taskId=u37fba000-d171-46b0-b616-e8d787b4032&title=&width=336) ## 自定义表单组件 若默认组件不满足需求,那么我们就需要自定义表单组件,自定义组件的步骤如下: 1. 继承DynamicFieldState,重写content或者build方法,必要时重写didChange方法,更改组件数据 ```dart class DynamicTextFieldState extends DynamicFieldState { @protected late TextEditingController controller; DynamicTextField get _widget => widget as DynamicTextField; @override Widget content() => TextField( controller: controller, keyboardType: _widget.inputType, inputFormatters: _widget.inputFormatters, style: _widget.contentStyle ?? context.bodyMediumStyle, textAlign: _widget.contentAlign ?? TextAlign.end, readOnly: _widget.readOnly ?? formItem.readOnly, enabled: !(_widget.readOnly ?? formItem.readOnly), onChanged: (newValue) { if (value is String?) { didChange(newValue as T); } }, maxLines: _widget.maxLines, minLines: _widget.minLines, maxLength: _widget.maxLength, decoration: _widget.contentDecoration ?? InputDecoration( isCollapsed: true, border: InputBorder.none, contentPadding: _widget.contentPadding ?? EdgeInsets.only(left: 8.w), hintText: _widget.hint, hintStyle: _widget.hintStyle, ), ); ... @override void didChange(T? value) { _updateText(value); super.didChange(value); } } ``` 2. 继承DynamicField,重写createState方法,返回1步骤中继承DynamicFieldState的类型 ```dart ///带文字输入框基础组件 /// ///@author lzj /// ///@since 2022/8/8 14:10 class DynamicTextField extends DynamicField { ///忽略属性代码 ... DynamicTextField({ super.key, ... }) :super(); @override DynamicTextFieldState createState() => DynamicTextFieldState(); } ```