Flutter练习(一)—Form表单校验实现登录功能

2,390 阅读3分钟

前言

最近想搞个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,则会返回到上一个路由。此属性通常用于拦截返回按钮。
  • onChangedForm的任意一个子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

FormStateFormState类,可以通过Form.of()GlobalKey获得。我们可以通过它来对Form的子孙FormField进行统一操作。我们看看其常用的三个方法:

  • FormState.validate():调用此方法后,会调用Form子孙FormField的validate回调,如果有一个校验失败,则返回false,所有校验失败项都会返回用户返回的错误提示。
  • FormState.save():调用此方法后,会调用Form子孙FormFieldsave回调,用于保存表单内容
  • 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)
                            }
                        },
                      ),
                    )
                  ],
                ),
              )
            ],
       )),
    );
  }
}