flutter3.0学习笔记

表单组件

Preview
  • 输入框TextField
  • controller 的使用
  • onChange的使用
  • focusNode 使用
  • decoration 自定义样式
  • 单选开关和复选框
  • 单选开关Switch
  • 复选框Checkbox
  • 单选 Radio
  • 表单Form
  • Form
  • TextFormField

输入框TextField

TextField用于文本输入,基本用法

const TextField(
  decoration: InputDecoration(
    labelText: '用户名',
    hintText: '请输入用户名',
    prefixIcon: Icon(Icons.person)
  ),
) 
TextField 属性属性介绍
controller编辑框的控制器,通过它可以设置/获取编辑框的内容、选择编辑内容、监听编辑文本改变事件
focusNode用于控制TextField是否占有当前键盘的输入焦点。它是我们和键盘交互的一个句柄(handle)
decoration用于控制TextField的外观显示,如提示文本、背景颜色、边框等
keyboardTypeTextInputType,键盘类型
textInputAction键盘动作按钮图标(即回车键位图标),它是一个枚举值,有多个可选值
textCapitalization大小写,默认为 TextCapitalization.none
style字体样式
strutStyle字体的布局样式
textAlign输入框内编辑文本在水平方向的对齐方式,默认TextAlign.start
textAlignVertical文字纵轴对齐方式
textDirectionTextDirection.ltr 是居左,TextDirection.rtl 是居右,和 textAlign 效果一致
readOnly只读属性,默认为 false
toolbarOptions长按时弹出的按钮设置,(如赋值,粘贴,全部选中等)
showCursor是否显示光标,默认为 true
autofocus是否自动聚焦,默认为 false
obscuringCharacter加密输入时的替换字符,默认为 '•'
obscureText是否加密,默认为 false
autocorrect是否自动更正,默认为 true
smartDashesTypeSmartDashesType 智能替换破折号,例如连续输入三个'-' 会自动替换成一个'——',当 obseretext == true 时,smartDashesType 默认不可用
smartQuotesTypeSmartQuotesType 智能替换引号,根据文字情况智能替换为左引号或者右引号,当 obseretext == true 时,SmartQuotesType 默认不可用
enableSuggestions是否在用户输入时显示输入建议,此标志仅影响Android,默认为 true
maxLines最大行数
minLines最小行数
expands是否填充父控件,默认为 false
maxLength最大长度
maxLengthEnforcement是否强制限制,或者只提供字符计数器和警告,默认为 true
onChanged输入框文字改变回调
onEditingComplete输入框完成回调
onSubmitted提交按钮点击回调
onAppPrivateCommand暂无
inputFormatters用于指定输入格式;当用户输入内容改变时,会根据指定的格式来校验,注意这里比 onChanged 先执行
enabled如果为false,则输入框会被禁用,禁用状态不接收输入和事件,同时显示禁用态样式(在其decoration中定义)
cursorWidth光标宽度,默认为 2.0
cursorHeight光标高度
cursorRadius光标圆角
cursorColor光标颜色
selectionHeightStyle选中高度样式,默认为 ui.BoxHeightStyle.tight
selectionWidthStyle选中宽度样式,默认为 ui.BoxWidthStyle.tight
keyboardAppearance键盘外观,此设置仅适用于iOS设备,iOS的白色以及黑色风格键盘
scrollPadding滚动后距离边缘的距离,默认为 EdgeInsets.all(20.0)
dragStartBehavior启动阻力,默认为 DragStartBehavior.start
enableInteractiveSelection默认为True,如果为false,则大多数辅助功能支持选择文本、复制和粘贴,移动插入符号将被禁用
selectionControls暂无
onTap点击事件
mouseCursor鼠标悬停,Web可以了解
buildCounterInputDecorator.counter 自定义小工具
scrollController滚动控制器
scrollPhysics滚动物理效果
autofillHints自动填充
clipBehavior暂无
restorationId暂无
scribbleEnabled暂无
enableIMEPersonalizedLearning暂无

keyboardType的枚举值:

keyboardType的枚举值介绍
text文本输入键盘
multiline多行文本,需和maxLines配合使用(设为null或大于1)
number数字;会弹出数字键盘
phone优化后的电话号码输入键盘;会弹出数字键盘并显示“* #”
datetime优化后的日期输入键盘;Android上会显示“: -”
emailAddress优化后的电子邮件地址;会显示“@ .”
url优化后的url输入键盘; 会显示“/ .”

controller 的使用

controller可以监听输入框变化,还可以设置默认值、选择文本。

(1)监听输入框变化 首先创建一个controller:

 final TextEditingController _controller =  TextEditingController();

然后设置输入框controller:

TextField(
    controller: _controller,
    decoration: const InputDecoration(
        labelText: '用户名',
        hintText: '请输入用户名',
        prefixIcon: Icon(Icons.person)
    ),
),
ElevatedButton(
  onPressed: (){
    //通过controller取值
    print(_controller.text);
  },
  child: const Text('完成')
),

(2)设置默认值、选择文本 创建一个新的controller:

 final TextEditingController _selectionController = TextEditingController();
//设置默认值
_selectionController.text = "设置默认值";
//选择文本
_selectionController.selection = TextSelection(
    baseOffset: 2,
    extentOffset: _selectionController.text.length
);

使用:

TextField(
    controller: _selectionController,
),

onChange的使用

//设置onChange回调
  TextField(
    controller: _controller,
    decoration: const InputDecoration(
        labelText: '用户名',
        hintText: '请输入用户名',
        prefixIcon: Icon(Icons.person)
    ),
    onChanged: (v){
         print("onChanged':$v");
    },
  ),

focusNode 使用

创建FocusNode对象实例:

 final FocusNode _focusNode = FocusNode();

监听焦点状态改变事件:

//输入框焦点事件的捕捉与监听
  @override
  void initState() {
    super.initState();
    // Add code after super
    //添加listen监听
    //对应的TextField失去或者获取焦点都会回调此监听
    _focusNode.addListener(() {
      bool hasFocus = _focusNode.hasFocus;
      bool hasListeners = _focusNode.hasListeners;
      //获得焦点时focusNode.hasFocus值为true,失去焦点时为false
      if(hasFocus){
        //获取焦点
        print('获取焦点 $hasFocus',);
      }else{
        //失去焦点
        print('失去焦点 $hasFocus',);
      }
    });
  }

运用:

 TextField(
  focusNode: _focusNode,//焦点名称
  decoration: const InputDecoration(
    labelText: '焦点',
  ),

),

decoration 自定义样式

我们可以通过decoration属性来定义输入框样式,先看一下decoration InputDecoration的构造:

 const InputDecoration({
    this.icon,
    this.iconColor,
    this.label,
    this.labelText,
    this.labelStyle,
    ...
  }) 

很多属性,就不一一举例了,

单选开关和复选框

单选开关Switch和复选框Checkbox,虽然它们都是继承自StatefulWidget,但它们本身不会保存当前选中状态,选中状态都是由父组件来管理的。当SwitchCheckbox被点击时,会触发它们的onChanged回调,我们可以在此回调中处理选中状态改变逻辑。

单选开关Switch

  • Switchmaterial风格的开关组件,基本用法如下: 1、定义变量来维护开关的状态:
bool _switchSelected = false; //维护单选开关状态
 Switch(
    value: _switchSelected,
    onChanged: (value){
      setState(() {
        _switchSelected = value;
      });
    }
)

效果:

image.png

我们来看一下基本属性:

const Switch({
    super.key,
    required this.value,
    required this.onChanged,//改变时触发
    this.activeColor,//激活时圆圈的颜色
    this.activeTrackColor,//激活时滑槽的颜色
    this.inactiveThumbColor,//非激活时圆圈的颜色
    this.inactiveTrackColor,//非激活时滑槽的颜色
    this.activeThumbImage,//圆圈图片设置,激活时效果
    this.onActiveThumbImageError,//打开状态下滑块图片加载失败回调
    this.inactiveThumbImage,//圆圈图片非激活效果
    this.onInactiveThumbImageError,关闭状态下滑块图片加载失败回调
    this.thumbColor,//可以通过不同状态设置滑块颜色
    this.trackColor,//可以通过不同状态设置轨道颜色
    this.materialTapTargetSize,//内边距,默认最小点击区域为 48 * 48,MaterialTapTargetSize.shrinkWrap 为组件实际大小
    this.dragStartBehavior = DragStartBehavior.start,//启动阻力
    this.mouseCursor,//鼠标的样式
    this.focusColor,//聚焦颜色
    this.hoverColor,//鼠标悬停时,外层的大圈颜色,一般用在web
    this.overlayColor,//设置按压滑动覆盖上面的颜色
    this.splashRadius,//大圈的半径,如果不想要外圈的悬浮效果,可以将半径设为 0 
    this.focusNode,//焦点控制
    this.autofocus = false,//是否自动聚焦
  })

激活和非激活的圆圈和滑槽的颜色设置

Switch(
    value: _switchSelected,
    onChanged: (value){
      setState(() {
        _switchSelected = value;
      });
    },
    activeColor: Colors.green,//激活时圆点颜色
    activeTrackColor: Colors.pink,//激活时滑槽颜色
    inactiveThumbColor: Colors.black,//非激活时圆点颜色
    inactiveTrackColor: Colors.yellow,//非激活时滑槽颜色
)

效果:

image.png

鼠标形状mouseCursor,用于web

 //mouseCursor: SystemMouseCursors.text,
 mouseCursor: SystemMouseCursors.grabbing,

圆圈图片设置:

 activeThumbImage: const AssetImage('images/avatar.jpg'),//激活时的圆圈图片
 inactiveThumbImage: const AssetImage('images/inactive.jpg'),//未激活时的圆圈图片

image.png

  • SwitchListTile 带标题开关
SwitchListTile(
  value: _switchSelected,
  onChanged: (value){
    setState(() {
      _switchSelected = value;
    });
  },
  title: const Text('今天是否开心'),
)

image.png

  • CupertinoSwitch ios风格开关
CupertinoSwitch(
  value: _switchSelected,
  onChanged: (value){
    setState(() {
      _switchSelected = value;
    });
  },
)

image.png

复选框Checkbox

1、定义变量来维护开关的状态 :

//Checkbox定义变量
 bool? _checkboxSelected = true;

基础用法:

Checkbox(
    value: _checkboxSelected,
    activeColor: Colors.pink,
    onChanged: (value){
      setState(() {
        _checkboxSelected = value;
      });
    }
)

image.png

我们看一下Checkbox的属性:

const Checkbox({
    super.key,
    required this.value,
    this.tristate = false, //设置复选框是否三态,取值包括true、false和 null
    required this.onChanged,////改变时触发
    this.mouseCursor,//鼠标样式
    this.activeColor,//选中时填充颜色
    this.fillColor,//设置单选框不同状态的的颜色
    this.checkColor,//选中时中间✔️颜色
    this.focusColor,//聚焦颜色
    this.hoverColor,//悬停颜色
    this.overlayColor,//按压覆盖颜色
    this.splashRadius,//光圈大小
    this.materialTapTargetSize,//内边距,默认最小点击区域为 48 * 48,MaterialTapTargetSize.shrinkWrap 为组件实际大小
    this.visualDensity,//布局紧凑设置
    this.shape,//形状
    this.side,//自定义选项框边框样式
  })

例子:

//属性列子
 Checkbox(
    value: _checkboxSelected,
    activeColor: Colors.pink,
   // fillColor: MaterialStateProperty.resolveWith((states) => null),
   // fillColor: MaterialStateProperty.all(Colors.cyan),//填充颜色
    checkColor: Colors.white,
    materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
   // shape: const CircleBorder(),//圆形
    //设置成圆角
    shape: const RoundedRectangleBorder(
      borderRadius: BorderRadius.all(Radius.circular(6))
    ),
    //设置未选择边框颜色
    side: const BorderSide(color: Colors.black,width: 2,style: BorderStyle.solid),
    visualDensity: const VisualDensity(
      horizontal: VisualDensity.minimumDensity,
      vertical: VisualDensity.minimumDensity
    ),
    onChanged: (value){
      setState(() {
        _checkboxSelected = value;
      });
    }
),

image.png

//多选列子

class FormPage extends StatefulWidget {
  const FormPage({Key? key}) : super(key: key);

  @override
  State<FormPage> createState() => _FormPageState();
}

class _FormPageState extends State<FormPage> {
  List flag = [false,false,false];
  List select = ['白玫瑰','红玫瑰','粉玫瑰'];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('表单之多选'),),
      body: Container(
        padding: const EdgeInsets.all(10.0),
        child: Column(
          children: [
          
            Row(
              children: [
                const Text('选择你喜欢的花'),
                Text(select[0]),
                Checkbox(
                    value: flag[0],
                    onChanged: (v){
                      setState(() {
                        flag[0] = v;
                      });
                    }
                ),
                Text(select[1]),
                Checkbox(
                    value: flag[1],
                    onChanged: (v){
                      setState(() {
                        flag[1] = v;
                      });
                    }
                ),
                Text(select[2]),
                Checkbox(
                    value: flag[2],
                    onChanged: (v){
                      setState(() {
                        flag[2] = v;
                      });
                    }
                ),
              ],
            ),
            ElevatedButton(
                onPressed: (){
                  String likes = '你选择的花是:';
                  for(int i = 0;i<flag.length;i++){
                    if(flag[i]){
                      likes = '${likes + select[i]} ';
                    }
                  }
                  print(likes);
                },
                child: const Text('你选择的花是')
            )
          ],
        ),
      ),
     
    );
  }
}

CheckboxListTile 实现全选和取消

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class FormPage extends StatefulWidget {
  const FormPage({Key? key}) : super(key: key);

  @override
  State<FormPage> createState() => _FormPageState();
}

class _FormPageState extends State<FormPage> {
  List flag = [false,false,false];
  List select = ['白玫瑰','红玫瑰','粉玫瑰'];
  bool isChecked = false;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('表单'),),
      body: Container(
        padding: const EdgeInsets.all(10.0),
        child: Column(
          children: [
            CheckboxListTile(
                title: const Text('全选'),
                secondary: const Icon(Icons.flag),///*设置显示的小组件,与□所在位置相反*/
                //调整复选框和图标的位置
                controlAffinity: ListTileControlAffinity.leading,
                value: isChecked,
                onChanged: (bool? value){
                  setState(() {
                    isChecked = value!;
                    for(int i = 0 ; i < flag.length; i++){
                      flag[i] = isChecked;
                    }
                   
                  });
                }
            ),
            CheckboxListTile(
                title:  Text(select[0]),
                secondary: const Icon(Icons.ac_unit_sharp),
                controlAffinity: ListTileControlAffinity.leading,
                value: flag[0],
                onChanged: (value){
                  setState(() {
                    flag[0] = value;
                  });
                }
            ),
            CheckboxListTile(
                title:  Text(select[1]),
                secondary: const Icon(Icons.ac_unit_sharp),
                controlAffinity: ListTileControlAffinity.leading,
                value: flag[1],
                onChanged: (value){
                  setState(() {
                    flag[1] = value;
                  });
                }
            ),
            CheckboxListTile(
                title:  Text(select[2]),
                secondary: const Icon(Icons.ac_unit_sharp),
                controlAffinity: ListTileControlAffinity.leading,
                value: flag[2],
                onChanged: (value){
                  setState(() {
                    flag[2] = value;
                  });
                }
            ),
            ElevatedButton(
                onPressed: (){
                  String likes = '你选择的花是:';
                  for(int i = 0;i<flag.length;i++){
                    if(flag[i]){
                      likes = '${likes + select[i]} ';
                    }
                  }
                  print(likes);
                },
                child: const Text('确定')
            ),
            
          ],
        ),
      ),
     
    );
  }
}

image.png

单选 Radio

Radio 属性介绍:

const Radio({
    super.key,
    required this.value,//@required 是否选中
    required this.groupValue,//@required 当前选中的值
    required this.onChanged,//@required 点击事件
    this.mouseCursor,//鼠标光标
    this.toggleable = false,//点击已选中按钮是否调用onChanged回调
    this.activeColor,//选中时填充颜色
    //其他的同Checkbox
    this.fillColor,
    this.focusColor,
    this.hoverColor,
    this.overlayColor,
    this.splashRadius,
    this.materialTapTargetSize,
    this.visualDensity,
    this.focusNode,
    this.autofocus = false,
  })

Radio基础用法:三个必填属性 定义一个性别变量:

int sex = 1;
child: Row(
 children: [
   const Text('女'),
   Radio(
       value: 1,
       groupValue: sex,
       onChanged: (value){
         print(value);
         setState(() {
           sex = value!;
         });
       }
   ),
   const Text('男'),
   Radio(
       value: 2,
       groupValue: sex,
       onChanged: (value){
         print(value);
         setState(() {
           sex = value!;
         });
       }
   )
 ],
),

表单Form

Form

Form组件是一个容器类控件,可以包含多个FormField表单控件,这样的好处是统一管理。 在使用Form的时候需要设置其key,通过key获取当前的FormState,然后可以调用FormStatesavevalidatereset等方法。Form继承自StatefulWidget对象,它对应的状态类为FormState。我们先看看Form类的定义:

const Form({
    super.key,
    required this.child,
    this.onWillPop,
    this.onChanged,
    AutovalidateMode? autovalidateMode,
  })
  • key 组件在整个 Widget树中的 key值。
  • onWillPop:决定Form所在的路由是否可以直接返回(如点击返回按钮),该回调返回一个Future对象,如果 Future 的最终结果是false,则当前路由不会返回;如果为true,则会返回到上一个路由。此属性通常用于拦截返回按钮。
  • onChangedForm的任意一个子FormField内容发生变化时会触发此回调。
  • autovalidateMode:自动校验。

TextFormField

Flutter 提供了一个TextFormField组件,它继承自FormField类,也是TextField的一个包装类,所以除了FormField定义的属性之外,它还包括TextField的属性:

TextFormField({
    ValueChanged<String>? onChanged,
    GestureTapCallback? onTap,
    VoidCallback? onEditingComplete,
    ValueChanged<String>? onFieldSubmitted,
    super.onSaved,//当 Form 表单调用保存方法 Save 时回调的函数
    super.validator,//Form 表单验证器 ,验证回调
    List<TextInputFormatter>? inputFormatters,
    ...
  })

TextFormField的基本用法:

TextFormField(
    onSaved: (value){
      print(value);
    },
    autovalidateMode: AutovalidateMode.always,
    validator: (value){
      return value!.trim().isNotEmpty ? null : "用户名不能为空";
    },
 )

onSaved是一个可选参数,当Form调用FormState.save时才会回调此方法。

validator验证函数,输入的值不匹配的时候返回的字符串显示在TextFielderrorText属性位置,返回null,表示没有错误。

完整例子:

import 'package:flutter/material.dart';

class LoginPage extends StatefulWidget {
  const LoginPage({Key? key}) : super(key: key);
  @override
  State<LoginPage> createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
final GlobalKey _formKey = GlobalKey<FormState>();
//通过controller获取input数据
  final TextEditingController _unameController = TextEditingController();
  final TextEditingController _pwdController = TextEditingController();
  Widget LoginFormWidget(){
    return Form(
      key: _formKey,//设置globalKey,用于后面获取FormState
      autovalidateMode: AutovalidateMode.onUserInteraction,//自动校验
      child: Column(
        children: [
          TextFormField(
            controller: _unameController,
            autofocus: true,//自动获取焦点
            decoration: InputDecoration(
              suffixIcon: IconButton(
                icon: const Icon(Icons.clear),
                onPressed: (){
                   _unameController.text = '';
                },
              ),
              labelText: "用户名",
              hintText: "填写用户名或者邮箱",
              icon: const Icon(Icons.person),

            ),
            //校验用户名
            validator: (v){
              return v!.trim().isNotEmpty ? null :'用户名不能为空';
            },
          ),
          TextFormField(
            controller: _pwdController,
            obscureText: true,
            decoration: InputDecoration(
              suffixIcon: IconButton(
                icon: const Icon(Icons.clear),
                onPressed: (){
                   _pwdController.text = '';
                },
              ),
              labelText: "密码",
              hintText: "填写密码",
              icon: const Icon(Icons.lock),

            ),
            //校验用户名
            validator: (v){
              return v!.trim().length >5  ? null :'密码不能少于6位';
            },
          ),

           Padding(
            padding: const EdgeInsets.only(top: 30.0),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(
                  onPressed:(){
                    // 通过_formKey.currentState 获取FormState后,
                    // 调用validate()方法校验用户名密码是否合法,校验
                    // 通过后再提交数据。
                    if((_formKey.currentState as FormState).validate()){
                      print(_unameController.text);
                      print(_pwdController.text);

                    }
                  } ,
                  child: const Text('登录')
                ),
                const SizedBox(width: 20,),
                ElevatedButton(
                  onPressed:(){
                    // 通过_formKey.currentState 获取FormState后,
                    // 调用validate()方法校验用户名密码是否合法,校验
                    // 通过后再提交数据。
                    if((_formKey.currentState as FormState).validate()){
                      print(_unameController.text);
                      print(_pwdController.text);

                    }
                  } ,
                  child: const Text('注册')
                )
              ],
            ),
          )
        ],
      ),
    );
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('表单实例'),),
      body: Container(
        padding: const EdgeInsets.all(20),
        child: LoginFormWidget(),
      ),
    );
  }
}

当 Form 表单调用保存方法:不需要controller获取

import 'package:flutter/material.dart';

class LoginPage extends StatefulWidget {
  const LoginPage({Key? key}) : super(key: key);

  @override
  State<LoginPage> createState() => _LoginPageState();
}


class _LoginPageState extends State<LoginPage> {
final GlobalKey _formKey = GlobalKey<FormState>();
  //通过controller获取input数据
  final TextEditingController _unameController = TextEditingController();
  final TextEditingController _pwdController = TextEditingController();

   String? userName; //用户名
   String? password; //密码


  Widget LoginFormWidget(){
    return Form(
      key: _formKey,//设置globalKey,用于后面获取FormState
      autovalidateMode: AutovalidateMode.onUserInteraction,//自动校验
      child: Column(
        children: [
          TextFormField(
           // controller: _unameController,
            autofocus: true,//自动获取焦点
            decoration: InputDecoration(
              suffixIcon: IconButton(
                icon: const Icon(Icons.clear),
                onPressed: (){},
              ),
              labelText: "用户名",
              hintText: "填写用户名或者邮箱",
              icon: const Icon(Icons.person),

            ),
            //校验用户名
            validator: (v){
              return v!.trim().isNotEmpty ? null :'用户名不能为空';
            },
            //当 Form 表单调用保存方法 Save时回调的函数。
            onSaved: (value){
              userName = value;
            },
            // 当用户确定已经完成编辑时触发
            onFieldSubmitted: (value){

            },
          ),
          TextFormField(
           // controller: _pwdController,
            obscureText: true,
            decoration: InputDecoration(
              suffixIcon: IconButton(
                icon: const Icon(Icons.clear),
                onPressed: (){},
              ),
              labelText: "密码",
              hintText: "填写密码",
              icon: const Icon(Icons.lock),

            ),
            //校验用户名
            validator: (v){
              return v!.trim().length >5  ? null :'密码不能少于6位';
            },
            //当 Form 表单调用保存方法 Save时回调的函数。
            onSaved: (value){
              password = value;
            },
            // 当用户确定已经完成编辑时触发
            onFieldSubmitted: (value){},
          ),

           Padding(
            padding: const EdgeInsets.only(top: 30.0),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(
                  onPressed:(){
                    // 通过_formKey.currentState 获取FormState后,
                    // 调用validate()方法校验用户名密码是否合法,校验
                    // 通过后再提交数据。
                    // if((_formKey.currentState as FormState).validate()){
                    //   print(_unameController.text);
                    //   print(_pwdController.text);
                    //
                    // }
                  } ,
                  child: const Text('登录')
                ),
                const SizedBox(width: 20,),
                ElevatedButton(
                  onPressed:(){
                    // 通过_formKey.currentState 获取FormState后,
                    var loginForm = _formKey.currentState as FormState;
                    //调用validate()方法校验用户名密码是否合法,校验
                    if(loginForm.validate()){
                        loginForm.save();
                        print('userName:${userName!},password:${password!}');
                    }
                    // 通过后再提交数据。
                    
                  } ,
                  child: const Text('调用save方法')
                ),
                const SizedBox(width: 20,),

                ElevatedButton(
                    onPressed:(){
                      // 通过_formKey.currentState 获取FormState后,
                      var loginForm = _formKey.currentState as FormState;
                      loginForm.reset();
                    } ,
                    child: const Text('重置')
                ),

              ],
            ),
          )
        ],
      ),
    );
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('表单实例'),),
      body: Container(
        padding: const EdgeInsets.all(20),
        child: LoginFormWidget(),
      ),
    );
  }
}