图文讲解表单组件,建立表单组件、校验表单、复杂表单、复杂校验规则、动态控制表单html
实现一个注册界面 git
上一次讲了登录界面&表单校验json
知道了表单和校验怎么写,回顾下api
Form组件函数(准确说叫widget),而后写一个key,由于咱们等下要操做它,而后写child,里面就是TextFormField组件。bash
new Form(
key: _formKey,
child: Column(children: [
TextFormField()
]
)
复制代码
TextFormField有validator校验函数 手机号校验例子:app
new TextFormField(
validator: (value){
RegExp reg = new RegExp(r'^1{1}\d{10}$');
if (!reg.hasMatch(value)) {
return '请输入正确的手机号码';
}else{
return null;
}
},
)
复制代码
这时候虽然有了validator,可是并无输入的载体,咱们须要加一个输入框async
final phone = new TextFormField(
keyboardType: TextInputType.number,
autofocus: false,
controller: _phone_controller,
onSaved: (val)=> this._phone = val,
validator: (value){
RegExp reg = new RegExp(r'^1{1}\d{10}$');
if (!reg.hasMatch(value)) {
return '请输入正确的手机号码';
}else{
return null;
}
},
decoration: new InputDecoration(
hintText: '手机号',
contentPadding: new EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: new OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
)
)
);
复制代码
这里的话,咱们加了一个keyboardType
,设置成了TextInputType.number
,这样调用的数数字键盘。ide
前面Form里面有一个key,可是咱们没有声明,须要声明下函数
GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
复制代码
而后form.validate()
检测有没有按规则填写,form.save()
是保存数据,这时候上面TextFormField
里面的onSaved
就会被调用,而后数据就被保存下来post
final form = _formKey.currentState;
if(form.validate()) {
form.save();
// 操做逻辑,刚刚的_phone字段就能够打印了,就是输入的手机号
}
复制代码
而后咱们就画UI、把上面的表单加上,点击注册的时候获取值,美滋滋。
可是这时候,点击发送验证码的时候,咱们无法拿到手机号,由于须要先.save的时候才能拿到值,这时候执行的时候也会触发校验规则,可是我只要手机号而已,怎么整。
建立一个控制器
TextEditingController mController=TextEditingController();
复制代码
TextFormField
里引入
TextFormField(
...
controller: mController
...
)
复制代码
点击发送验证码的时候,获取手机号
mController.text
复制代码
我靠,完美。可是... 好像这时候缺乏了校验,因此上面方案不能用。
这时候,咱们须要写两个Form组件,也就是在phone组件外面再加一个Form组件
phone组件
改为
new Form( key: _phone_form_key, child: phone, ),
两个Form格式以下
new Form(
key: _formKey,
child: Container(
padding: EdgeInsets.only(left: 24.0, right: 24.0),
child: Column(
children: <Widget>[
代码
Container(
color: Colors.white,
child: new Form(
key: _phone_form_key,
child: phone,
),
),
代码
)
)
)
复制代码
这时候发送验证码的表单就搞完了,咱们就能够注册。
注册完成后返回上一个路由而且传递参数
(这时候返回的上一个页面也就是登陆页)
登陆页拿到手机号后,要在输入框出现手机号,这样用户就不用再次输入手机号了。(有些app是注册没有密码,而后直接帮他登陆,密码是手机号后四位数,而后弹窗肯定是否修改密码,不修改直接登陆成功)
返回到上页面,把手机号传递过去
// 注册成功 转跳到登录页面
Navigator.pop(context, _phone);
复制代码
这时候登陆页就须要接收手机号, 上一页页面进入下一个页面的时候有路由转跳,返回的时候,第二个参数值回返回回来。
登陆页点击注册的按钮添加事件
onRigister() async{
final result = await Navigator.pushNamed(context, '/rigister');
_phone_controller.text = result;
}
复制代码
_phone_controller.text = result;
复制代码
这个_phone_controller
就是phone组件的控制器,控制器上面介绍了。
_phone_controller.text
这个便可以获取值,也能够设置值,很强大。
若是要实现确认密码,那么在validator
里面,调用 密码1和密码2的控制器,.text就能够拿到值判断了。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:cjyy/utils/http.dart';
import 'package:cjyy/utils/toast.dart';
import 'dart:convert';
import '../login/index.dart';
class registerPage extends StatefulWidget {
@override
_registerPageState createState() => new _registerPageState();
}
class _registerPageState extends State<registerPage> {
bool isButtonEnable=true; //按钮状态 是否可点击
String buttonText='发送验证码'; //初始文本
int count=60; //初始倒计时时间
Timer timer; //倒计时的计时器
TextEditingController mController=TextEditingController();
// 提交
GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
GlobalKey<FormState> _phone_form_key = new GlobalKey<FormState>();
String _phone = '';
String _pw = '';
String _code = '';
// 密码显示、隐藏
bool _isObscure = true;
Color _eyeColor;
void _buttonClickListen() async{
if(isButtonEnable){ //当按钮可点击时
final form = _phone_form_key.currentState;
if(form.validate()){
form.save();
// if(!new RegExp(r"1{1}\d{10}").hasMatch(_phone)){
// Toast.show("手机号格式错误哦", context);
// print(_phone);
// return null;
// }
String response_content = await HTTP('get:sendSms', {
"phone":_phone,
});
Map<String, Object> response_map = jsonDecode(response_content);
if(response_map['code'] != 200){
print('发送验证码失败');
Toast.show(response_map['msg'], context);
return null;
}
// 验证码发送成功
isButtonEnable=false; //按钮状态标记
_initTimer();
setState(() {
isButtonEnable=false; //按钮状态标记
_initTimer();
});
return null; //返回null按钮禁止点击
}
}
return null;
}
@override
void initState() {
super.initState();
}
void _initTimer(){
timer = new Timer.periodic(Duration(seconds: 1), (Timer timer) {
count--;
setState(() {
if(count==0){
timer.cancel(); //倒计时结束取消定时器
isButtonEnable=true; //按钮可点击
count=60; //重置时间
buttonText='发送验证码'; //重置按钮文本
}else{
buttonText='从新发送($count)'; //更新文本内容
}
});
});
}
@override
void dispose() {
timer?.cancel(); //销毁计时器
timer=null;
super.dispose();
}
@override
Widget build(BuildContext context) {
final phone = new TextFormField(
keyboardType: TextInputType.number,
autofocus: false,
initialValue: '',
onSaved: (val)=> this._phone = val,
// onEditingComplete: () => {},
validator: (value){
RegExp reg = new RegExp(r'^1{1}\d{10}$');
if (!reg.hasMatch(value)) {
return '请输入正确的手机号码';
}else{
return null;
}
},
decoration: new InputDecoration(
hintText: '手机号',
contentPadding: new EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: new OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
)
)
);
final password = new TextFormField(
autofocus: false,
initialValue: '',
onSaved: (val)=> this._pw = val,
obscureText: _isObscure,
validator: (value){
if(value.length < 6 || value.length > 16){
return '密码在6-16位数之间哦';
}else{
return null;
}
},
decoration: new InputDecoration(
hintText: '密码',
contentPadding: new EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: new OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
suffixIcon: IconButton(
icon: Icon(
Icons.remove_red_eye,
color: _eyeColor,
),
onPressed: () {
setState(() {
_isObscure = !_isObscure;
_eyeColor = _isObscure
? Colors.grey
: Theme.of(context).iconTheme.color;
});
}),
),
);
onsubmit() async{
final form = _formKey.currentState;
final phoneform = _phone_form_key.currentState;
// // 测试 注册成功 转跳到登录页面
// Navigator.pop(context, 'test');
if(phoneform.validate() && form.validate()) {
form.save();
phoneform.save();
print('注册中');
print(_phone);
print(_pw);
String response_content = await HTTP('get:phone_rigist', {
"phone":_phone,
"pass": _pw,
"code": _code,
});
Map<String, Object> response_map = jsonDecode(response_content);
if(response_map['code'] != 200){
print('注册异常');
Toast.show(response_map['msg'], context);
return;
}
// 注册成功 转跳到登录页面
Navigator.pop(context, _phone);
}
}
return Container(
child: Scaffold(
appBar: AppBar(
brightness: Brightness.light,
title: Text('注册'),
),
body: new Form(
key: _formKey,
child: Container(
padding: EdgeInsets.only(left: 24.0, right: 24.0),
child: Column(
children: <Widget>[
Container(height: 200,),
Container(
color: Colors.white,
// padding: EdgeInsets.only(left: 10,right: 10),
child: new Form(
key: _phone_form_key,
child: phone,
),
),
Container(
// height: 70,
color: Colors.white,
padding: EdgeInsets.only(top: 10, bottom: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
// crossAxisAlignment: CrossAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.ideographic,
children: <Widget>[
// Text('验证码',style: TextStyle(fontSize: 13,color: Color(0xff333333)),),
Expanded(
child: TextFormField(
keyboardType: TextInputType.number,
// maxLines: 6,
// maxLength: 1,
onSaved: (value) => this._code = value,
validator: (value){
if(value.length != 4){
return '验证码至少4位数';
}
return null;
},
controller: mController,
textAlign: TextAlign.left,
// inputFormatters: [WhitelistingTextInputFormatter.digitsOnly,LengthLimitingTextInputFormatter(6)],
decoration: InputDecoration(
hintText: ('填写验证码'),
contentPadding: new EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
// contentPadding: EdgeInsets.only(top: -5,bottom: 0),
hintStyle: TextStyle(
color: Color(0xff999999),
fontSize: 13,
),
alignLabelWithHint: true,
// border: OutlineInputBorder(borderSide: BorderSide.none),
border: new OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
),
)
),
Container(
margin: EdgeInsets.only(left: 20),
width: 120,
child: FlatButton(
disabledColor: Colors.grey.withOpacity(0.1), //按钮禁用时的颜色
disabledTextColor: Colors.white, //按钮禁用时的文本颜色
textColor:isButtonEnable?Colors.white:Colors.black.withOpacity(0.2), //文本颜色
color: isButtonEnable?Color(0xff44c5fe):Colors.grey.withOpacity(0.1), //按钮的颜色
splashColor: isButtonEnable?Colors.white.withOpacity(0.1):Colors.transparent,
shape: StadiumBorder(side: BorderSide.none),
onPressed: (){ setState(() {
_buttonClickListen();
});},
// child: Text('从新发送 (${secondSy})'),
child: Text('$buttonText',style: TextStyle(fontSize: 13,),),
),
),
],
),
),
password,
Container(
width: double.infinity,
height: 45,
margin: EdgeInsets.only(top: 50),
child: RaisedButton(
onPressed: () {
onsubmit();
},
shape: StadiumBorder(side: BorderSide.none),
color: Color(0xff44c5fe),
child: Text(
'注册',
style: TextStyle(color: Colors.white,fontSize: 15),
),
),
),
],
)
)
)
),
);
}
}
复制代码