Flutter表单管理插件flutter_reactive_form的使用
Flutter表单管理插件flutter_reactive_form的使用
最低要求
- Dart SDK: >=2.18.6 <4.0.0
- Flutter: >=1.17.0
安装和使用
一旦你熟悉了Flutter,可以将flutter_reactive_form
添加到pubspec.yaml
文件的依赖项列表中:
dependencies:
flutter:
sdk: flutter
flutter_reactive_form: ^0.0.1
然后在控制台运行命令flutter packages get
。
创建一个表单
一个表单由多个字段控件组成。要声明一个包含name
和birthday
字段的表单,可以按如下方式编写:
final form = ReactiveForm(
onChanged: (formData, fieldChanged) {
/// 处理更改。
},
formGroup: {
"name": FormFieldControl<String>(
fieldEnum: "name",
name: "Name",
isRequired: true,
isEnabled: true,
data: "Nghi",
),
"birthday": FormFieldControl<DateTime?>(
fieldEnum: "birthday",
name: "Birthday",
isRequired: true,
isEnabled: true,
data: null,
),
},
);
如何获取和设置表单数据
你可以获取字段的值:
String get name => _reactiveForm.getFieldData<String>(fieldEnum: 'name');
DateTime? get birthday => _reactiveForm.getFieldData<DateTime>(fieldEnum: 'birthday');
要设置字段的值:
_reactiveForm.setFieldData(fieldEnum: 'name', data: "Kate");
验证
设置验证规则如下:
_reactiveForm.setFormatValidationMap({
'birthday': (birthday) {
if (birthday == null || birthday.isAfter(DateTime.now())) {
return "The time is invalid";
}
return '';
},
});
验证一个字段:
final fieldControl = _reactiveForm.getField(fieldEnum: 'name');
final error = _reactiveForm.validateFormatField(fieldControl!);
验证整个表单:
final errors = _reactiveForm.validateFormatFields();
使用mixin
ReactiveFormMixin
中提供了与表单内部交互的可用函数:
class ProfileFormController with ReactiveFormMixin {
/// 在state.initState()中调用
void init() {
final form = ReactiveForm(
onChanged: (formData, fieldChanged) {
/// 处理更改。
},
formGroup: {
"name": FormFieldControl<String>(
fieldEnum: "name",
name: "Name",
isRequired: true,
isEnabled: true,
data: "Nghi",
),
"birthday": FormFieldControl<DateTime?>(
fieldEnum: "birthday",
name: "Birthday",
isRequired: true,
isEnabled: true,
data: null,
),
},
);
initForm(form);
setFormatValidationMap({
'birthday': (birthday) {
if (birthday == null || birthday.isAfter(DateTime.now())) {
return "The time is invalid";
}
return '';
},
});
}
/// 与UI交互
String? getName() {
return getFieldData<String>(fieldEnum: 'name');
}
DateTime? getBirthday() {
return getFieldData<DateTime>(fieldEnum: 'birthday')!;
}
void setName(String name) {
setFieldData(fieldEnum: 'name', data: name);
}
void setBirthday(DateTime birthday) {
setFieldData(fieldEnum: 'birthday', data: birthday);
}
}
完整示例代码
以下是一个完整的示例代码,展示了如何使用flutter_reactive_form
创建和管理表单:
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:flutter/material.dart';
import 'package:flutter_reactive_form/flutter_reactive_form.dart';
import 'package:mvc_pattern/mvc_pattern.dart';
enum ProfileFieldEnum {
fullName("Full Name"),
email("Email"),
gender("Gender");
final String label;
const ProfileFieldEnum(this.label);
}
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final profileController = ProfileController();
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: ProfileScreen(controller: profileController),
);
}
}
class ProfileScreen extends StatefulWidget {
const ProfileScreen({
Key? key,
required this.controller,
}) : super(key: key);
final ProfileController controller;
[@override](/user/override)
_ProfileScreenState createState() => _ProfileScreenState(controller);
}
class _ProfileScreenState extends StateMVC<ProfileScreen> {
_ProfileScreenState(ProfileController controller) : super(controller) {
_controller = controller;
}
late ProfileController _controller;
[@override](/user/override)
void initState() {
super.initState();
_controller.onInit();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Profile')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _controller.formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
controller: _controller.fullNameController,
decoration: InputDecoration(labelText: ProfileFieldEnum.fullName.label),
onChanged: _controller.onFullNameChanged,
validator: _controller.validateFullName,
),
TextFormField(
controller: _controller.emailController,
decoration: InputDecoration(labelText: ProfileFieldEnum.email.label),
onChanged: _controller.onEmailNameChanged,
validator: _controller.validateEmail,
),
DropdownButtonFormField<String>(
decoration: InputDecoration(labelText: ProfileFieldEnum.gender.label),
value: _controller.getFieldData(fieldEnum: ProfileFieldEnum.gender.name),
items: ['Male', 'Female'].map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: _controller.onGenderChanged,
validator: _controller.validateGender,
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: ElevatedButton(
onPressed: _controller.create,
child: Text('Create'),
),
),
],
),
),
),
);
}
[@override](/user/override)
void dispose() {
_controller.onDispose();
super.dispose();
}
}
class ProfileController extends ControllerMVC with ReactiveFormMixin {
final formKey = GlobalKey<FormState>();
late final TextEditingController fullNameController;
late final TextEditingController emailController;
void onInit() {
/// 初始化文本字段的文本。
String initialFullName = '';
String initialLastName = '';
String initialGender = 'Male';
fullNameController = TextEditingController(text: initialFullName);
emailController = TextEditingController(text: initialLastName);
final form = ReactiveForm(
onChanged: (formData, fieldChanged) {
/// 处理更改。
},
formGroup: {
ProfileFieldEnum.fullName.name: FormFieldControl<String?>(
fieldEnum: ProfileFieldEnum.fullName.name,
name: ProfileFieldEnum.fullName.label,
isRequired: true,
isEnabled: true,
data: initialFullName, // 初始值。
),
ProfileFieldEnum.email.name: FormFieldControl<String?>(
fieldEnum: ProfileFieldEnum.email.name,
name: ProfileFieldEnum.email.label,
isRequired: true,
isEnabled: true,
data: initialLastName, // 初始值。
),
ProfileFieldEnum.gender.name: FormFieldControl<String?>(
fieldEnum: ProfileFieldEnum.gender.name,
name: ProfileFieldEnum.gender.label,
isRequired: true,
isEnabled: true,
data: initialGender, // 初始值。
),
},
);
form.setFormatValidationMap({
ProfileFieldEnum.fullName.name: (value) {
assert(value is String?, " The value must be string.");
final fullname = value as String?;
if (fullname == null || fullname.isEmpty) {
return "Please enter your full name";
}
return null;
},
ProfileFieldEnum.email.name: (value) {
assert(value is String?, " The value must be string.");
final email = value as String?;
if (email == null || email.isEmpty) {
return "Please enter an email";
} else if (!(value?.contains('@') ?? false)) {
return 'Email must contain the "@" character';
}
return null;
},
ProfileFieldEnum.gender.name: (value) {
assert(value is String?, " The value must be string.");
final gender = value as String?;
if (gender == null || gender.isEmpty) {
return "Please choose Gender";
}
return null;
},
});
initForm(form);
}
void onFullNameChanged(String? value) {
setFieldData(fieldEnum: ProfileFieldEnum.fullName.name, data: value);
}
void onEmailNameChanged(String? value) {
setFieldData(fieldEnum: ProfileFieldEnum.email.name, data: value);
}
void onGenderChanged(String? value) {
setFieldData(fieldEnum: ProfileFieldEnum.gender.name, data: value);
refresh();
}
String? validateFullName(String? value) {
final fullNameControl = getField(fieldEnum: ProfileFieldEnum.fullName.name)!;
return validateFormatField(fullNameControl, value: value);
}
String? validateEmail(String? value) {
final emailControl = getField(fieldEnum: ProfileFieldEnum.email.name)!;
return validateFormatField(emailControl, value: value);
}
String? validateGender(String? value) {
final genderControl = getField(fieldEnum: ProfileFieldEnum.gender.name)!;
return validateFormatField(genderControl, value: value);
}
void create() {
if (formKey.currentState!.validate()) {
// 验证成功后的逻辑
final fullName = getFieldData<String>(fieldEnum: ProfileFieldEnum.fullName.name);
final email = getFieldData<String>(fieldEnum: ProfileFieldEnum.email.name);
final gender = getFieldData<String>(fieldEnum: ProfileFieldEnum.gender.name);
print("fullName: $fullName, email: $email, gender: $gender");
// 执行Profile操作(例如API调用)
}
}
void onDispose() {
fullNameController.dispose();
emailController.dispose();
}
}
更多关于Flutter表单管理插件flutter_reactive_form的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter表单管理插件flutter_reactive_form的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
flutter_reactive_form
是一个用于管理 Flutter 表单的插件,它基于响应式编程思想,可以帮助开发者更轻松地管理和验证表单数据。以下是如何使用 flutter_reactive_form
的基本步骤和示例。
1. 添加依赖
首先,在 pubspec.yaml
文件中添加 flutter_reactive_form
依赖:
dependencies:
flutter:
sdk: flutter
flutter_reactive_form: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get
来安装依赖。
2. 创建表单模型
flutter_reactive_form
使用 FormGroup
来管理表单的字段。你可以通过继承 FormGroup
来创建自定义的表单模型。
import 'package:flutter_reactive_form/flutter_reactive_form.dart';
class MyForm extends FormGroup {
MyForm() {
addControl('username', FormControl<String>(value: '', validators: [Validators.required]));
addControl('email', FormControl<String>(value: '', validators: [Validators.required, Validators.email]));
addControl('password', FormControl<String>(value: '', validators: [Validators.required, Validators.minLength(6)]));
}
}
3. 在 UI 中使用表单
在 UI 中,你可以使用 ReactiveForm
和 ReactiveTextField
来绑定表单字段。
import 'package:flutter/material.dart';
import 'package:flutter_reactive_form/flutter_reactive_form.dart';
class MyFormPage extends StatelessWidget {
final MyForm form = MyForm();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Reactive Form Example')),
body: ReactiveForm(
formGroup: form,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
ReactiveTextField<String>(
formControlName: 'username',
decoration: InputDecoration(labelText: 'Username'),
validationMessages: {
'required': (error) => 'Username is required',
},
),
SizedBox(height: 16),
ReactiveTextField<String>(
formControlName: 'email',
decoration: InputDecoration(labelText: 'Email'),
validationMessages: {
'required': (error) => 'Email is required',
'email': (error) => 'Please enter a valid email',
},
),
SizedBox(height: 16),
ReactiveTextField<String>(
formControlName: 'password',
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
validationMessages: {
'required': (error) => 'Password is required',
'minLength': (error) => 'Password must be at least 6 characters',
},
),
SizedBox(height: 24),
ElevatedButton(
onPressed: () {
if (form.valid) {
// Form is valid, process the data
print('Form is valid');
print('Username: ${form.control('username').value}');
print('Email: ${form.control('email').value}');
print('Password: ${form.control('password').value}');
} else {
// Form is invalid, show errors
print('Form is invalid');
}
},
child: Text('Submit'),
),
],
),
),
),
);
}
}
4. 处理表单提交
在 onPressed
回调中,你可以检查表单的有效性,并处理表单数据。如果表单无效,你可以显示错误信息或执行其他操作。
5. 自定义验证器
flutter_reactive_form
支持自定义验证器。你可以通过 ValidatorFn
来创建自定义的验证逻辑。
ValidatorFn customValidator = (control) {
if (control.value != 'expectedValue') {
return {'customError': true};
}
return null;
};
// 使用自定义验证器
addControl('customField', FormControl<String>(value: '', validators: [customValidator]));
6. 动态表单字段
你可以在运行时动态添加或移除表单字段。
form.addControl('newField', FormControl<String>(value: ''));
form.removeControl('newField');
7. 表单状态监听
你可以监听表单的状态变化,例如表单的有效性、字段的值变化等。
form.statusChanges.listen((status) {
print('Form status: $status');
});
form.control('username').valueChanges.listen((value) {
print('Username changed: $value');
});
8. 表单重置
你可以通过 reset
方法重置表单字段的值和状态。
form.reset();