Flutter for OpenHarmony:formz 简化表单验证逻辑,分离 UI 与业务状态(声明式表单验证) 深度解析与鸿蒙适配指南
本文介绍了在OpenHarmony平台上使用formz库构建表单验证的解决方案。formz通过将每个表单字段封装为独立验证对象,简化了表单状态管理。文章详细讲解了formz的核心理念、基础用法和核心API,包括单一字段验证、多字段联合验证以及如何结合状态管理。特别针对OpenHarmony平台,提供了输入法适配和焦点管理的建议。最后通过一个完整的登录表单示例,展示了如何实现邮箱和密码验证,并控制提
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

前言
在 Flutter 应用开发中,表单验证是一个高频且容易变复杂的场景。传统的 Form + GlobalKey 方式在大型应用中往往导致代码耦合度高、难以测试。
formz 提供了一种基于声明式编程模型的轻量级表单验证解决方案。它将每个输入字段封装为独立的验证对象,不仅简化了验证逻辑,还使得表单状态管理(如结合 Bloc 或 Provider)变得异常清晰。本文将详细介绍如何在 OpenHarmony 上使用 formz 构建健壮的表单。
一、formz 简介
1.1 核心理念
formz 的核心思想是将每个表单字段视为一个拥有自身状态的对象。每个字段包含:
- 当前值 (
value) - validation status (
valid,invalid) - error message (如果有)
这种设计使得你可以在 UI 之外编写和测试验证逻辑,非常适合 MVVM 或 Bloc 架构。
1.2 OpenHarmony 适配情况
formz 是一个纯 Dart 逻辑库,没有任何原生平台依赖。因此,它可以在 OpenHarmony 上直接使用,无需任何特殊配置。
二、集成与基础用法
2.1 添加依赖
在 pubspec.yaml 中添加:
dependencies:
formz: ^0.8.0
2.2 定义验证模型
你需要继承 FormzInput 来定义每个字段的验证规则。
import 'package:formz/formz.dart';
// 定义可能的验证错误
enum EmailValidationError { invalid }
// 创建 Email 输入模型
class Email extends FormzInput<String, EmailValidationError> {
// 纯净状态(初始状态)
const Email.pure() : super.pure('');
// 修改后状态(脏状态)
const Email.dirty([super.value = '']) : super.dirty();
// 验证逻辑
EmailValidationError? validator(String value) {
return value.contains('@') ? null : EmailValidationError.invalid;
}
}
三、核心 API 详解与示例
3.1 示例一:单一字段验证
演示如何使用刚才定义的 Email 模型。
void validateEmail() {
// 1. 初始状态
const emailPure = Email.pure();
print('Is valid: ${emailPure.isValid}'); // false (因为初始为空且规则要有@)
// 2. 输入变更
const emailInvalid = Email.dirty('invalid-email');
print('Error: ${emailInvalid.error}'); // EmailValidationError.invalid
// 3. 有效输入
const emailValid = Email.dirty('test@example.com');
print('Is valid: ${emailValid.isValid}'); // true
print('Value: ${emailValid.value}');
}

3.2 示例二:多字段联合验证
通常表单包含多个字段,formz 可以轻松检查整体状态。
import 'package:formz/formz.dart';
void checkFormStatus() {
final email = Email.dirty('test@example.com');
final password = Password.dirty('secure123'); // 假设定义了 Password 类
// ✅ 推荐:使用 Formz.validate 检查列表
final inputs = [email, password];
final status = Formz.validate(inputs);
if (status) {
print('表单整体有效,可以提交');
} else {
print('表单存在无效字段');
}
}

3.3 示例三:结合状态管理
这里展示如何在简单的 ChangeNotifier 中使用 formz。
class LoginFormState extends ChangeNotifier {
Email _email = const Email.pure();
Password _password = const Password.pure();
Email get email => _email;
Password get password => _password;
// 检查是否所有字段都有效
bool get isValid => Formz.validate([_email, _password]);
void emailChanged(String value) {
_email = Email.dirty(value);
notifyListeners();
}
void passwordChanged(String value) {
_password = Password.dirty(value);
notifyListeners();
}
}

四、OpenHarmony 平台适配
4.1 输入法适配
在 OpenHarmony 上,处理键盘遮挡是常见问题。建议配合 SingleChildScrollView 或 Scaffold 的 resizeToAvoidBottomInset 属性使用。
Scaffold(
resizeToAvoidBottomInset: true, // 键盘弹出时调整大小
body: SingleChildScrollView(
child: LoginForm(),
),
)
4.2 焦点管理
OpenHarmony 对焦点控制支持良好。使用 FocusNode 可以提升用户体验,例如输完邮箱后点击键盘上的 “Next” 自动跳到密码框。
五、完整实战示例:登录表单
本示例构建一个完整的登录页面,包含邮箱和密码验证,以及提交按钮的状态控制。
5.1 示例代码
首先定义 password 模型:
enum PasswordValidationError { empty }
class Password extends FormzInput<String, PasswordValidationError> {
const Password.pure() : super.pure('');
const Password.dirty([super.value = '']) : super.dirty();
PasswordValidationError? validator(String value) {
return value.isNotEmpty ? null : PasswordValidationError.empty;
}
}
完整页面代码:
import 'package:flutter/material.dart';
import 'package:formz/formz.dart';
// 引入之前定义的 Email 和 Password 模型...
void main() {
runApp(const MaterialApp(home: LoginPage()));
}
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final _key = GlobalKey<FormState>();
late Email _email;
late Password _password;
bool _status = false; // 表单整体状态
void initState() {
super.initState();
_email = const Email.pure();
_password = const Password.pure();
}
void _onEmailChanged(String value) {
setState(() {
_email = Email.dirty(value);
_status = Formz.validate([_email, _password]);
});
}
void _onPasswordChanged(String value) {
setState(() {
_password = Password.dirty(value);
_status = Formz.validate([_email, _password]);
});
}
void _submit() {
if (_status) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('登录中...')),
);
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Formz Login 示例')),
body: Padding(
padding: const EdgeInsets.all(24.0),
child: Form(
key: _key,
child: Column(
children: [
TextFormField(
initialValue: _email.value,
decoration: InputDecoration(
labelText: '邮箱',
errorText: _email.isPure
? null
: (_email.error == EmailValidationError.invalid ? '无效的邮箱地址' : null),
border: const OutlineInputBorder(),
),
onChanged: _onEmailChanged,
keyboardType: TextInputType.emailAddress,
),
const SizedBox(height: 16),
TextFormField(
initialValue: _password.value,
decoration: InputDecoration(
labelText: '密码',
errorText: _password.isPure
? null
: (_password.error == PasswordValidationError.empty ? '密码不能为空' : null),
border: const OutlineInputBorder(),
),
obscureText: true,
onChanged: _onPasswordChanged,
),
const SizedBox(height: 24),
SizedBox(
width: double.infinity,
height: 48,
child: ElevatedButton(
onPressed: _status ? _submit : null, // 仅当有效时启用
child: const Text('登录'),
),
),
],
),
),
),
);
}
}

六、总结
formz 通过将验证逻辑与 UI 解耦,极大地提升了代码的可维护性和测试性。在 OpenHarmony 开发中,它是构建复杂表单的理想选择,特别是配合 Bloc 或 Provider 使用时。
最佳实践:
- 为每个输入字段创建独立的
FormzInput类。 - 将验证逻辑移出 Widget,保持 UI 层的纯净。
- 利用
Formz.validate统一管理表单提交状态。
更多推荐



所有评论(0)