欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Flutter学习笔记(14)--App结构和导航组件

程序员文章站 2022-04-23 09:19:42
表单组件是个包含表单元素的区域,表单元素允许用户输入内容,比如:文本区域,下拉表单,单选框、复选框等,常见的应用场景有:登陆、注册、输入信息等。表单里有两个重要的组件,一个是Form组件用来做整个表单提交使用的,另一个是TextFormField组件用来做用户输入的。 ......

如需转载,请注明出处:flutter学习笔记(13)--表单组件

表单组件是个包含表单元素的区域,表单元素允许用户输入内容,比如:文本区域,下拉表单,单选框、复选框等,常见的应用场景有:登陆、注册、输入信息等。表单里有两个重要的组件,一个是form组件用来做整个表单提交使用的,另一个是textformfield组件用来做用户输入的。

form组件属性
属性 类型 说明
key key 组件在整个widget树中的key值
autovalidate bool 是否自动提交表单
child widget 组件child只能有一个组件
onchange voidcallback 当formfield值改变时的回调函数

 

 

 

 

 

 

 

textformfiled组件属性
属性名 类型 说明
autovalidate bool 自动验证值
initalvalue t 表单字段初始值,比如:输入收获地址时,默认回填本的地址信息
onsaved formfieldsetter<t> 当form表单调用保存方法save时回调的函数
validator formfieldvalidator<t> form表单验证器

 

 

 

 

 

 

 

 

 

对于输入框我们最关心的时输入内容是否合法,比如邮箱地址是否正确,电话号码是否是数字等等,等用户输入完成后,我们需要知道输入框输入的内容。那么我们要如何才能获取到表单对象呢?为了获取表单的实例,我们需要设置一个全局类型的key,通过这个key的属性,来获取表单对象:

 

globalkey<formstate> globalkey = new globalkey<formstate>();

 

我们来简单的写一个登陆页面,校验输入框内的内容,当内容不合法时,并给出相应的提示:

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

void main() => runapp(demoapp());

class demoapp extends statefulwidget{
  @override
  _demoappstate createstate() => new _demoappstate();
}

class _demoappstate extends state<demoapp> {
  string username;
  string userpwd;
  globalkey<formstate> globalkey = new globalkey<formstate>();
  void check(){
    var loginform = globalkey.currentstate;
    //验证表单
    if(loginform.validate()){
      loginform.save();
      fluttertoast.showtoast(msg: '信息提交成功',toastlength: toast.length_long,gravity: toastgravity.bottom,textcolor: colors.white);
    }
  }
  @override
  widget build(buildcontext context) {
    return new materialapp(
      debugshowcheckedmodebanner: false,
      title: 'from表单demo',
      home: new scaffold(
        appbar: new appbar(
          title: new text('form表单demo'),
          leading: icon(icons.menu,size: 30,),
          actions: <widget>[
            iconbutton(icon: icon(icons.search),iconsize: 30, onpressed: null)
          ],
        ),
        body: new column(
          children: <widget>[
            new form(
              key: globalkey,
              child: new column(
                children: <widget>[
                  new textformfield(
                    decoration: new inputdecoration(
                      labeltext: '请输入用户名',
                    ),
                    onsaved: (value){
                      username = value;
                    },
                  ),
                  new textformfield(
                    decoration: new inputdecoration(
                      contentpadding: edgeinsets.only(left: 20,top: 10,right: 0,bottom: 0),
                      hinttext: '请输入密码',
                      hintstyle: new textstyle(fontsize: 30,color: colors.amberaccent)
                    ),
                    obscuretext: true,
                    validator: (value){
                      return value.length < 6 ? '密码长度不够6位' : null;
                    },
                    onsaved: (value){
                      userpwd = value;
                    },
                  )
                ],
              ),
            ),
            new container(
              margin: new edgeinsets.symmetric(vertical: 20,horizontal: 0),
              width: 330,
              height: 50,
              child: new sizedbox(
                child: new raisedbutton(
                  onpressed: check,
                  child: new text(
                    '确定',
                    style: new textstyle(
                        fontsize: 20,
                        color: colors.white
                    ),
                  ),
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
}

 

先看一下上面代码的效果截图,然后我会给大家讲一下代码的内容

Flutter学习笔记(14)--App结构和导航组件                                    Flutter学习笔记(14)--App结构和导航组件

写的比较丑,大家见谅,主要是因为我想多试试一些属性怎么用,总之是要多尝试嘛~

上面是输入内容前和输入内容后的对比图,从直观的表象上可以看的出来,用户名输入框输入内容后,提示内容被挤到上面去了,而密码输入框输入内容后提示内容则消失了,这是因为两个输入框提示语的text的类型使用的不同,用户名:labeltext,密码:hinttext,这两个都有style属性,都可以对默认的提示内容字体进行属性设置。在点击确认按钮后,会调用check()方法,在check()方法中提交表单验证,这时候会触发密码输入框中的validator: (value),从而实现我们密码输入框内容的校验,这个就是textfromfield中的验证回调方法,在表单验证的时候,会先验证这个方法中的逻辑判断,如果验证失败返回错误信息,如果验证通过则返回null。


 

接下来的内容有兴趣的可以继续看一下,我想以android中写xml的布局方式理解一下flutter中的页面构建,因为我前面一直是在写简单的组件demo,还没有形成一个完整的构建意识,以下是我个人的理解,如果有不对的地方,还请留言批评、指正,不胜感谢!!!

从整个页面来构思的话,可以看做是一个大容器,容器里面有三个组件,分别是两个输入框和一个按钮,这3个组件是垂直方向排列的,写android的同学看到这个页面,很容易就会想到最外层放一个linearlayout或者是一个relativelayout,然后在里面垂直方向放上两个edittext和一个button,再写一下控件的属性的就完事儿了,其实写flutter也是这种思想。

注:在这里我先说明以下在flutter中child里面只能放一个widget,children可以放多个widget。

我们来把android和flutter对比着理解,这样应该可以更容易理解一点,也更直观一点:

1.android:最外层垂直方向的linearlayout或relativelayout。

   flutter:最外层body我们new了一个column(column也是一个容器,类似于container)

2.android:放上两个edittext和一个button

   flutter:容器放置好了,我们要开始往容器里面加组件元素了,因为容器里面我们要放置多个组件,所以我们要使用children,children里面放一个form表单和一个button,在form表单里面,我们要放两个输入框,而且是垂直方向放置的,想到这里是不是就该先考虑怎么把方向设置好呢?所以form表单里的第一层widget就要放置一个column容器,容器里面放两个输入框,既然是两个,那么是不是两个输入框就应该被一个children包裹起来呢?

总的来说:根widget(column)->children(里面包含form和button)->form表单(第一层)->child(column)->children(里面包含了两个输入框textformfield)->textformfield(第三层)

 

最后看一下按钮部分的代码,说明一下为什么外面要包一层container

new container(
              margin: new edgeinsets.symmetric(vertical: 20,horizontal: 0),
              width: 330,
              height: 50,
              child: new sizedbox(
                child: new raisedbutton(
                  onpressed: check,
                  child: new text(
                    '确定',
                    style: new textstyle(
                        fontsize: 20,
                        color: colors.white
                    ),
                  ),
                ),
              ),
            )

之所以最外层包了个container,是因为sizedbox和raisebutton这两个组件都没有margin或padding属性,所以ui上要想控制边距等操作,这是一种处理方式。

 

也不知道我上面大白话写了那么多,能不能表达清楚我的意思,如果有没看懂的,还麻烦留言提问吧!!!

 

下一章节:flutter学习笔记(14)--app结构和导航组件