前言
最近想搞个flutter项目,起初,照着 flutter_wechat抄了一下聊天工具,但是里面有很多细节点不是很了解,对于我这种刚接触flutter的小白,总感觉心有余而力不足,最近又在掘金中看到有些大佬仿掘金搞了个掘金的博客网站,于是退而求其次,想照着掘金ui及api搞一个掘金博客
在传统html中,我们一般做表单校验都是用form表单,flutter也一样
Form组件相关API
在此,我直接将Form
组件Api放与此处:
Form
Form
继承自StatefulWidget
对象,它对应的状态类为FormState
。我们先看看Form
类的定义:
Form({
@required Widget child,
bool autovalidate = false,
WillPopCallback onWillPop,
VoidCallback onChanged,
})
autovalidate
:是否自动校验输入内容;当为true
时,每一个子FormField内容发生变化时都会自动校验合法性,并直接显示错误信息。否则,需要通过调用FormState.validate()
来手动校验。onWillPop
:决定Form
所在的路由是否可以直接返回(如点击返回按钮),该回调返回一个Future
对象,如果Future的最终结果是false
,则当前路由不会返回;如果为true
,则会返回到上一个路由。此属性通常用于拦截返回按钮。onChanged
:Form
的任意一个子FormField
内容发生变化时会触发此回调。
FormField
Form
的子孙元素必须是FormField
类型,FormField
是一个抽象类,定义几个属性,FormState
内部通过它们来完成操作,FormField
部分定义如下:
const FormField({
...
FormFieldSetter<T> onSaved, //保存回调
FormFieldValidator<T> validator, //验证回调
T initialValue, //初始值
bool autovalidate = false, //是否自动校验。
})
为了方便使用,Flutter提供了一个TextFormField
组件,它继承自FormField
类,也是TextField
的一个包装类,所以除了FormField
定义的属性之外,它还包括TextField
的属性。
FormState
FormState
为Form
的State
类,可以通过Form.of()
或GlobalKey
获得。我们可以通过它来对Form
的子孙FormField
进行统一操作。我们看看其常用的三个方法:
FormState.validate()
:调用此方法后,会调用Form
子孙FormField的validate
回调,如果有一个校验失败,则返回false,所有校验失败项都会返回用户返回的错误提示。FormState.save()
:调用此方法后,会调用Form
子孙FormField
的save
回调,用于保存表单内容FormState.reset()
:调用此方法后,会将子孙FormField
的内容清空。
具体操作
因此,利用form表单进行表单校验,我们主要有以下三个步骤
- 构造form表单
- 校验函数
- 点击时触发校验
构造form表单
final _formKey = GlobalKey<FormState>();
TextEditingController _uNameController = new TextEditingController();
TextEditingController _pwdController = new TextEditingController();
校验函数
这里我们只放校验手机号的一部分代码
class ValidatorUtils {
/// 精确验证是否是手机号
static bool isMobileExact(String input) {
return matches(RegexConstants.REGEX_MOBILE_EXACT, input);
}
/// 返回输入是否匹配正则表达式。
static bool matches(String regex, String input) {
if (input.isEmpty) {
return false;
}
return RegExp(regex).hasMatch(input);
}
}
class RegexConstants{
static const String REGEX_MOBILE_EXACT =
"^((13[0-9])|(14[579])|(15[0-35-9])|(16[2567])|(17[0-35-8])|(18[0-9])|(19[0-35-9]))\d{8}$";
}
点击按钮触发校验
onTap: () => {
// 登陆接入
if ((_formKey.currentState as FormState).validate())
{
// 验证通过提交数据(登录)
print(_uNameController.text),
print(_pwdController.text)
}
},
表单完整代码如下
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_application/pages/common/bar/common_bar.dart';
import 'package:flutter_application/pages/common/button/common_button.dart';
import 'package:flutter_application/utils/validator_utils.dart';
class LoginPage extends StatefulWidget {
@override
_LoginState createState() => _LoginState();
}
class _LoginState extends State<LoginPage> {
@override
Widget build(BuildContext context) {
final _formKey = GlobalKey<FormState>();
TextEditingController _uNameController = new TextEditingController();
TextEditingController _pwdController = new TextEditingController();
return new Scaffold(
resizeToAvoidBottomInset: false, // 键盘弹起引起的挤压问题
appBar: CommonBar(title: 'Login'),
body: Container(
padding: EdgeInsets.fromLTRB(12.0, 12, 12.0, 0),
child: Column(
children: [
Image.asset('assets/images/juejin_logo.png'),
Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
TextFormField(
controller: _uNameController,
decoration: InputDecoration(
labelText: '用户名',
hintText: '手机号', //邮箱
icon: Icon(CupertinoIcons.person)),
validator: (value) {
bool status = ValidatorUtils.isMobileExact(value!);
if (!status) {
return '请输入正确的手机号';
}
return null;
},
),
TextFormField(
controller: _pwdController,
obscureText: true,
decoration: InputDecoration(
hintText: '密码',
labelText: '密码',
icon: Icon(CupertinoIcons.lock)),
),
// 登陆按钮
Container(
margin: EdgeInsets.fromLTRB(0, 50, 0, 0),
child: CommonButton(
text: '登陆',
onTap: () => {
// 登陆接入
if ((_formKey.currentState as FormState).validate())
{
// 验证通过提交数据(登录)
print(_uNameController.text),
print(_pwdController.text)
}
},
),
)
],
),
)
],
)),
);
}
}