Flutter-表单Widget

作者: WinJayQ | 来源:发表于2020-04-18 17:12 被阅读0次

    1.TextField的使用

    1.1. TextField的介绍

    TextField用于接收用户的文本输入,它提供了非常多的属性,我们来看一下源码:

    const TextField({
      Key key,
      this.controller,
      this.focusNode,
      this.decoration = const InputDecoration(),
      TextInputType keyboardType,
      this.textInputAction,
      this.textCapitalization = TextCapitalization.none,
      this.style,
      this.strutStyle,
      this.textAlign = TextAlign.start,
      this.textAlignVertical,
      this.textDirection,
      this.readOnly = false,
      ToolbarOptions toolbarOptions,
      this.showCursor,
      this.autofocus = false,
      this.obscureText = false,
      this.autocorrect = true,
      this.maxLines = 1,
      this.minLines,
      this.expands = false,
      this.maxLength,
      this.maxLengthEnforced = true,
      this.onChanged,
      this.onEditingComplete,
      this.onSubmitted,
      this.inputFormatters,
      this.enabled,
      this.cursorWidth = 2.0,
      this.cursorRadius,
      this.cursorColor,
      this.keyboardAppearance,
      this.scrollPadding = const EdgeInsets.all(20.0),
      this.dragStartBehavior = DragStartBehavior.start,
      this.enableInteractiveSelection = true,
      this.onTap,
      this.buildCounter,
      this.scrollController,
      this.scrollPhysics,
    })
    

    我们来学习几个比较常见的属性:

    • 一些属性比较简单:keyboardType键盘的类型,style设置样式,textAlign文本对齐方式,maxLength最大显示行数等等;
    • decoration:用于设置输入框相关的样式
      • icon:设置左边显示的图标
      • labelText:在输入框上面显示一个提示的文本
      • hintText:显示提示的占位文字
      • border:输入框的边框,默认底部有一个边框,可以通过InputBorder.none删除掉
      • filled:是否填充输入框,默认为false
      • fillColor:输入框填充的颜色
    • controller:
    • onChanged:监听输入框内容的改变,传入一个回调函数
    • onSubmitted:点击键盘中右下角的down时,会回调的一个函数

    1.2. TextField的样式以及监听

    import 'package:flutter/material.dart';
    
    main(List<String> args) {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text("HelloWorld"),
            ),
            body: MyHomeBody(),
          ),
        );
      }
    }
    
    class MyHomeBody extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Container(
          padding: EdgeInsets.all(20),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              TextFieldDemo()
            ],
          ),
        );
      }
    }
    
    class TextFieldDemo extends StatefulWidget {
      @override
      _TextFieldDemoState createState() =>  _TextFieldDemoState();
    }
    
    class _TextFieldDemoState extends State<TextFieldDemo> {
      @override
      Widget build(BuildContext context) {
        return TextField(
          decoration: InputDecoration(
            icon: Icon(Icons.people),
            labelText: "username",
            hintText: "请输入用户名",
            border: InputBorder.none,
            filled: true,
            fillColor: Colors.lightGreen
          ),
          onChanged: (value){
            print("onChange:$value");
          },
          onSubmitted: (value){
            print("onSubmitted:$value");
          } ,
        );
      }
    }
    
    image.png

    1.3. TextField的controller

    我们可以给TextField添加一个控制器(Controller),可以使用它设置文本的初始值,也可以使用它来监听文本的改变
    事实上,如果我们没有为TextField提供一个Controller,那么会Flutter会默认创建一个TextEditingController的,这个结论可以通过阅读源码得到:

    override
      void initState() {
        super.initState();
        // ...其他代码
        if (widget.controller == null)
          _controller = TextEditingController();
      }
    

    我们也可以自己来创建一个Controller控制一些内容:

    class _TextFieldDemoState extends State<TextFieldDemo> {
      final textEditingController = TextEditingController();
    
      @override
      void initState() {
        super.initState();
    
        // 1.设置默认值
        textEditingController.text = "Hello World";
    
        // 2.监听文本框
        textEditingController.addListener(() {
          print("textEditingController:${textEditingController.text}");
        });
      }
        
      // ...省略build方法
    }
    
    image.png

    2. Form表单的使用

    在我们开发注册、登录页面时,通常会有多个表单需要同时获取内容或者进行一些验证,如果对每一个TextField都分别进行验证,是一件比较麻烦的事情。

    做过前端的开发知道,我们可以将多个input标签放在一个form里面,Flutter也借鉴了这样的思想:我们可以通过Form对输入框进行分组,统一进行一些操作。

    2.1. Form表单的基本使用

    Form表单也是一个Widget,可以在里面放入我们的输入框。
    但是Form表单中输入框必须是FormField类型的

    • 我们查看刚刚学过的TextField是继承自StatefulWidget,并不是一个FormField类型;
    • 我们可以使用TextFormField,它的使用类似于TextField,并且是继承自FormField的;

    我们通过Form的包裹,来实现一个注册的页面:

    import 'package:flutter/material.dart';
    
    main(List<String> args) {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text("HelloWorld"),
            ),
            body: MyHomeBody(),
          ),
        );
      }
    }
    
    class MyHomeBody extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Container(
          padding: EdgeInsets.all(20),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              FormDemo()
            ],
          ),
        );
      }
    }
    
    class FormDemo extends StatefulWidget {
      @override
      _FormDemoState createState() =>  _FormDemoState();
    }
    
    class _FormDemoState extends State<FormDemo> {
    
      @override
      Widget build(BuildContext context) {
        return Form(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              TextFormField(
                decoration: InputDecoration(
                  icon: Icon(Icons.people),
                  labelText: "用户名或手机号"
                ),
              ),
              TextFormField(
                obscureText: true,
                decoration: InputDecoration(
                  icon: Icon(Icons.lock),
                  labelText: "密码"
                ),
              ),
              SizedBox(height: 16,),
              Container(
                width: double.infinity,
                height: 44,
                child: RaisedButton(
                  color: Colors.lightGreen,
                  child: Text("注册",style: TextStyle(fontSize: 20,color: Colors.white),),
                  onPressed: (){
                    print("点击了注册按钮");
                  },
                ),
              ),
            ],
          ),
        );
      }
    }
    
    image.png

    2.2. 保存和获取表单数据

    有了表单后,我们需要在点击注册时,可以同时获取和保存表单中的数据,怎么可以做到呢?

    • 1)需要监听注册按钮的点击,在之前我们已经监听的onPressed传入的回调中来做即可。(当然,如果嵌套太多,我们待会儿可以将它抽取到一个单独的方法中)
    • 2)监听到按钮点击时,同时获取用户名和密码的表单信息。

    如何同时获取用户名和密码的表单信息?

    • 如果我们调用Form的State对象的save方法,就会调用Form中放入的TextFormField的onSave回调:
    TextFormField(
      decoration: InputDecoration(
        icon: Icon(Icons.people),
        labelText: "用户名或手机号"
      ),
      onSaved: (value) {
        print("用户名:$value");
      },
    ),
    

    但是,我们有没有办法可以在点击按钮时,拿到 Form对象 来调用它的save方法呢?

    知识点:在Flutter如何可以通过一个引用获取一个StatefulWidget的State对象呢?

    答案:通过绑定一个GlobalKey即可。

    import 'package:flutter/material.dart';
    
    main(List<String> args) {
     runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
     @override
     Widget build(BuildContext context) {
       return MaterialApp(
         home: Scaffold(
           appBar: AppBar(
             title: Text("HelloWorld"),
           ),
           body: MyHomeBody(),
         ),
       );
     }
    }
    
    class MyHomeBody extends StatelessWidget {
     @override
     Widget build(BuildContext context) {
       return Container(
         padding: EdgeInsets.all(20),
         child: Column(
           mainAxisAlignment: MainAxisAlignment.center,
           children: <Widget>[
             FormDemo()
           ],
         ),
       );
     }
    }
    
    class FormDemo extends StatefulWidget {
     @override
     _FormDemoState createState() =>  _FormDemoState();
    }
    
    class _FormDemoState extends State<FormDemo> {
    
     final registerFormKey = GlobalKey<FormState>();
     String username,password;
    
     void registerForm(){
       registerFormKey.currentState.save();
       print("username:$username password:$password");
     }
    
    
     @override
     Widget build(BuildContext context) {
       return Form(
         key: registerFormKey,
         child: Column(
           mainAxisAlignment: MainAxisAlignment.center,
           children: <Widget>[
             TextFormField(
               decoration: InputDecoration(
                 icon: Icon(Icons.people),
                 labelText: "用户名或手机号"
               ),
               onSaved: (value){
                 this.username = value;
               },
             ),
             TextFormField(
               obscureText: true,
               decoration: InputDecoration(
                 icon: Icon(Icons.lock),
                 labelText: "密码"
               ),
               onSaved: (value){
                 this.password = value;
               },
             ),
             SizedBox(height: 16,),
             Container(
               width: double.infinity,
               height: 44,
               child: RaisedButton(
                 color: Colors.lightGreen,
                 child: Text("注册",style: TextStyle(fontSize: 20,color: Colors.white),),
                 onPressed: registerForm,
               ),
             ),
           ],
         ),
       );
     }
    }
    
    
    
    
    image.png

    2.3. 验证填写的表单数据

    在表单中,我们可以添加验证器,如果不符合某些特定的规则,那么给用户一定的提示信息

    比如我们需要账号和密码有这样的规则:账号和密码都不能为空。
    按照如下步骤就可以完成整个验证过程:

    • 1)为TextFormField添加validator的回调函数;
    • 2)调用Form的State对象的validate方法,就会回调validator传入的函数;


      image.png

    也可以为TextFormField添加一个属性:autovalidate

    • 不需要调用validate方法,会自动验证是否符合要求;


      image.png

    学习内容来自Flutter从入门到实战

    相关文章

      网友评论

        本文标题:Flutter-表单Widget

        本文链接:https://www.haomeiwen.com/subject/akebvhtx.html