阅读 891

flutter - 图文讲解表单组件基本使用 & 注册实战

图文讲解表单组件,创建表单组件、校验表单、复杂表单、复杂校验规则、动态控制表单

实现一个注册界面

上一次讲了登陆界面&表单校验

知道了表单和校验怎么写,回顾下

创建表单组件

创建form组件

Form组件函数(准确说叫widget),然后写一个key,因为我们等下要操作它,然后写child,里面就是TextFormField组件。

new Form(
  key: _formKey,
  child: Column(children: [
    TextFormField()
  ]
)
复制代码

填写校验规则

TextFormField有validator校验函数 手机号校验例子:

new TextFormField(
    validator: (value){
        RegExp reg = new RegExp(r'^1{1}\d{10}$');
        if (!reg.hasMatch(value)) {
          return '请输入正确的手机号码';
        }else{
          return null;
        }
    },
)
复制代码

这时候虽然有了validator,但是并没有输入的载体,我们需要加一个输入框

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,这样调用的数数字键盘。

触发校验规则

前面Form里面有一个key,但是我们没有声明,需要声明下

GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
复制代码

然后form.validate()检测有没有按规则填写,form.save()是保存数据,这时候上面TextFormField里面的onSaved就会被调用,然后数据就被保存下来

final form = _formKey.currentState;
if(form.validate()) {
  form.save();
  // 操作逻辑,刚刚的_phone字段就可以打印了,就是输入的手机号
}
复制代码

然后我们就画UI、把上面的表单加上,点击注册的时候获取值,美滋滋。
但是这时候,点击发送验证码的时候,我们没法拿到手机号,因为需要先.save的时候才能拿到值,这时候执行的时候也会触发校验规则,但是我只要手机号而已,怎么整。

发送验证码

控制器

创建一个控制器

TextEditingController mController=TextEditingController();
复制代码

TextFormField里引入

TextFormField(
    ...
    controller: mController
    ...
)
复制代码

点击发送验证码的时候,获取手机号

mController.text
复制代码

我靠,完美。但是... 好像这时候缺少了校验,所以上面方案不能用。

嵌套Form

这时候,我们需要写两个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),
                    ),
                  ),
                ),
              ],
            )
          )
        )
      ),
    );
  }
}

复制代码

相关链接

TextFormField组件官方文档

关注下面的标签,发现更多相似文章
评论