Flutter 常用Widget-输入框

Material design组件提供了两种输入框,分别是TextField和TextFormField。他们的作用都是使用户可以使用硬件键盘或屏幕键盘输入文本。

TextField

每当用户更改字段中的文本时,文本字段就会调用onChanged回调。如果用户已完成在字段中的键入(例如,通过按软键盘上的按钮),则文本字段将调用onSubmitted回调。

要控制在文本字段中显示的文本,就要使用controller。例如,要设置文本字段的初始值,请使用已经包含一些文本的controller。

默认情况下,TextField具有默认修饰,该修饰在TextField下方绘制分隔线。您可以使用decoration属性来控制装饰,例如,通过添加标签或图标。如果将decoration属性设置为null,则装饰将被完全删除。

如果装饰非空(这是默认值),则TextField要求其父节点是material widget。轻击TextField时,触发涟漪效果。

要将TextField与其他FormField集成到Form中,请考虑使用TextFormField。

TextFormField

TextFormField继承FormField包含一个TextField。TextFormField使得重置或验证多个字段变得更加容易。 要在没有表单的情况下使用,请将GlobalKey传递给构造函数,然后使用GlobalKey.currentState保存或重置表单字段。

指定controller后,TextEditingController.text定义initialValue。 如果FormField是延迟构造其子级的滚动容器的一部分,例如ListView或CustomScrollView,则应指定一个控制器。 控制器的生存期应由滚动容器的有状态widget父节点管理。

如果未指定控制器,则可以使用initialValue为自动生成的控制器提供初始值。

Controller

我们在来看看controller,通过它可以设置/获取编辑框的内容、选择编辑内容、监听编辑文本改变事件。大多数情况下我们都需要显式提供一个controller来与文本框交互。如果没有提供controller,则TextField内部会自动创建一个。

class TextFieldPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: TextField(
            onChanged: (value) {
              print("value $value");
            },
            decoration: InputDecoration(
              labelText: "请输入用户名",
              hintText: "我是暗示",
              prefixIcon: Icon(Icons.person),
            ),
          ),
        ),
      ),
    );
  }
}

获取输入内容

  • onChange 上面的代码中已经使用了这个办法
  • controller 
// 创建controller
TextEditingController _controller = TextEditingController();
_controller.text="我是默认值";
// 设置controller
TextField(
  controller: _selectionController,
)

我们来看完整代码

class TextFieldPage extends StatelessWidget {
  final TextEditingController _controller = TextEditingController();
  TextFieldPage() {
    _controller.addListener(() {
      print(_controller.text);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: TextField(
            controller: _controller,
            onChanged: (value) {
              print("value $value");
            },
            decoration: InputDecoration(
              labelText: "请输入用户名",
              hintText: "我是暗示",
              prefixIcon: Icon(Icons.person),
            ),
          ),
        ),
      ),
    );
  }
}

两种方式相比,onChanged是专门用于监听文本变化,而controller的功能却多一些,比如设置默认值、选择文本等。

对于输入框,我们在开发中可能最关心的还是输入的内容是否合法,比如电话号是否合法,邮箱是否合法等。这个时候就要用到我们的表单Form 和 TextFormField了。

Form组件主要属性

属性 类型 说明
key Key Widget树中的key
autovalidate bool 自动提交表单
child Widget 组件的child
onChanged

VoidCallback

当FormField值改变回调函数
... ... ...

TextFormField主要属性

属性 类型 说明
key Key Widget树中的key
autovalidate bool 自动验证
initialValue T 初始值
onSaved FormFieldSetter<T> Form调用保存方法回调
validator FormFieldValidator<T> Form表单验证
... ... ...

要想获得表单,我们需要设置一个全局类型的key,通过这个key的属性来获取表单对象。关于key,我会在另外的文章中介绍。

class TextFieldPage extends StatelessWidget {
  final GlobalKey<FormState> _globalKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            Form(
              key: _globalKey,
              child: TextFormField(
                onSaved: (value) {
                  print("onSaved $value");
                },
                validator: (value) {
                  print("onSaved $value");
                  return value.length < 4 ? "长度不够" : null;
                },
                decoration: InputDecoration(
                  labelText: "请输入用户名",
                  hintText: "我是暗示",
                  prefixIcon: Icon(Icons.person),
                ),
              ),
            ),
            RaisedButton(
              child: Text('登陆'),
              onPressed: () {
                if (_globalKey.currentState.validate()) {
                  print('登陆成功');
                }
              },
            ),
          ],
        ),
      ),
    );
  }
}

整理一下,这里使用了Form,FormField,FormState

  • Form继承自StatefulWidget对象,它对应的状态类为FormState。
  • FormStateFormState类,可以通过Form.of()GlobalKey获得。我们可以通过它来对Form的子FormField进行统一操作。
  • FormField是一个抽象类,定义几个属性,FormState内部通过它们来完成操作。TextFormField继承FormField。也是TextField的一个包装类,所以除了FormField定义的属性之外,它还包括TextField的属性。

值得注意的是,如果使用Form.of()来获得FormState需要在Form的子节点中,包含一层Builder参数,此时返回的context才是可以获取到父节点的context。

总结:今天介绍了如何使用TextField或者Form加TextFormField来实现输入框功能,controller以及一些基本的回调函数,还要注意使用Form的表单的获取方式等。接下来的文章会继续将常用Widget逐一介绍,在最后的系列中,会公开一个商业级的项目,感兴趣的小伙伴关注。如果您在阅读过程中发现错误,请及时留言给我,我会第一时间改正。也欢迎大家一切交流,共同进步,感谢支持!

猜你喜欢

转载自blog.csdn.net/z2008q/article/details/108529860