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

Flutter基础Widget使用----动画图解输入框

程序员文章站 2022-05-30 10:15:40
...

输入框同样是UI组成的必要部分,比如常见的登陆场景,需要输入用户名和密码,多个输入框组成在一起就成了一个表单了。在 Flutter 中输入框是由 TextField Widget实现的,而表单是由 Form Widget实现的。

一、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,
    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,
    this.onTap,
    this.buildCounter,
    this.scrollController,
    this.scrollPhysics,
  })

controller ---- 控制正在编辑的文本,它是 TextEditingController 类型。

focusNode ---- 定义此 Widget 的键盘焦点。

decoration ---- 在 TextField 周围显示的装饰。默认情况下,在文本字段下绘制一条水平线,但可以配置为显示图标,标签,提示文本和错误文本。

keyboardType ---- TextInputType 枚举类,用于设置该输入框默认的键盘输入类型,在Android上,行为可能会因设备和键盘提供商而异。

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

textInputAction ---- 用于键盘的操作按钮的类型。

enum TextInputAction {
  /// 逻辑含义:当前输入源(例如 [TextField] )没有相关的输入操作。
  none,
  /// 逻辑含义:让操作系统决定最合适的操作。
  unspecified,
  /// 逻辑含义:用户完成向一组输入(如表单)提供输入的操作。现在应该发生某种终结行为。
  done,
  /// 逻辑含义:用户输入了一些代表目的地的文本,例如餐馆名称。
  /// “go”按钮旨在将用户带到与该目的地相对应的应用程序部分。
  go,
  /// 逻辑含义:执行搜索查询。
  search,
  /// 逻辑含义:发送用户撰写的内容,例如电子邮件或短信。
  send,
  /// 逻辑含义:用户已完成当前输入源的操作,并希望移至下一个输入源。
  next,
  /// 逻辑含义:用户希望返回到组中的上一个输入源,例如,具有多个[TextField]的表单。
  previous,
  /// 逻辑含义:在iOS应用中,通常会在屏幕顶部显示“返回”按钮和“继续”按钮。 
  continueAction,
  /// 逻辑含义:用户想加入某些东西,例如无线网络。
  join,
  /// 逻辑含义:用户想要路线选择,例如,驾驶路线。
  route,
  /// 逻辑含义:启动对紧急服务的呼叫。
  emergencyCall,
  /// 逻辑含义:在焦点文本输入中插入换行符,例如 [TextField]。
  newline,
}

textCapitalization ---- 配置平台键盘如何选择大写或小写键盘。

enum TextCapitalization {
  /// 每个单词的第一个字母默认为大写的键盘。
  words,
  /// 每个句子的首字母默认为大写的键盘。
  sentences,
  /// 每个字符默认为大写的键盘。
  characters,
  /// 默认为小写键盘。
  none,
}

style ---- TextStyle 类型,之前在 Text Widget 一节中已经详细说明。

strutStyle ---- StrutStyle 类型,之前在 Text Widget 一节中已经详细说明。

textAlign ---- 如何水平对齐文本。

enum TextAlign {
  /// 将文本在容器的左边缘对齐。
  left,
  /// 在容器的右边缘对齐文本。
  right,
  /// 在容器的中心对齐文本。
  center,
  /// 文本的延伸行,以填充容器宽度的软换行结束。
  /// 以换行符结束的行与[开始]边缘对齐。
  justify,
  /// 将文本在容器的前端对齐。
  start,
  /// 将文本在容器的尾部对齐。
  end,
}

textAlignVertical ---- 输入中文本的垂直对齐方式。

/// 将TextField的输入Text与TextField中的最高位置对齐。
static const TextAlignVertical top = TextAlignVertical(y: -1.0);
/// 将TextField的输入Text对齐到TextField的中心。
static const TextAlignVertical center = TextAlignVertical(y: 0.0);
/// 将TextField的输入Text与TextField中最底部的位置对齐。
static const TextAlignVertical bottom = TextAlignVertical(y: 1.0);

textDirection ---- 文字方向,是从左向右,还是从右向左(例如阿拉伯语、希伯来语)。

readOnly ---- 是否只读。

showCursor ---- 是否显示光标。

autofocus ---- 是否自动获取焦点。

obscureText ---- 是否隐藏正在编辑的文本(例如,用于密码)。

autocorrect ---- 是否启用自动校正。

maxLines ---- 最大行数。

minLines ---- 最小行数。

expands ---- 此 Widget 的高度是否将调整大小以填充其父级。

maxLength ---- 文本字段中允许的最大字符数。

maxLengthEnforced ---- 如果为 true,则阻止该 Widget 允许超过 [maxLength] 个字符。如果设置了 [maxLength],则 [maxLengthEnforced] 指示是否强制执行限制,或者仅在超过 [maxLength] 时提供字符计数器和警告。

onChanged ---- 输入框内容改变时的回调函数。

onEditingComplete ---- 当用户提交可编辑的内容时调用(例如,用户按下键盘上的“完成”按钮)。

onSubmitted ---- 当用户指示他们已完成字段中文本的编辑时调用。

inputFormatters ---- 可选的输入验证和格式化替代。文本输入更改时,格式化程序将按提供的顺序运行。

enabled ---- 如果为false,则文本字段为“禁用”:它将忽略点击,其 [decoration] 呈现为灰色。

cursorWidth ---- 光标宽度。

cursorRadius ---- 光标圆角。

cursorColor ---- 光标颜色。

keyboardAppearance ---- 键盘的外观。仅在iOS设备上支持此设置。

scrollPadding ---- 当 Textfield 滚动到视图中时,将 padding 配置为围绕 [Scrollable] 的边缘。

当此 Widget 获得焦点并且不完全可见时(例如,部分滚动到屏幕外或被键盘重叠),则它将尝试通过滚动周围的 [Scrollable](如果有)来使其自身可见。此值控制 TextField 在滚动之后将距 [Scrollable] 边缘的距离。

dragStartBehavior ---- 设置确定用户开始拖动时拖动何时正式开始。

enableInteractiveSelection ---- 如果为true,则长按此TextField将选择文本并显示 剪切/复制/粘贴菜单,而点击将移动文本插入符号。如果为false,则将禁用用于选择文本、复制和粘贴以及移动插入符号的大多数辅助功能支持。

onTap ---- 当用户点击此文本字段时调用。

buildCounter ---- 生成自定义 [InputDecorator.counter] Widget 的回调。有关传递的参数的说明,请参见 [InputCounterWidgetBuilder]。返回的 Widget 将放置在该行下方,以代替指定 [counterText] 时构建的默认 Widget。

scrollController ---- 垂直滚动时要使用的 [ScrollController](可用于控制此 Widget 滚动到的位置的对象)。如果为null,它将实例化一个新的ScrollController。

scrollPhysics ---- 垂直滚动时要使用的 [ScrollPhysics](Widget 应如何响应用户输入) 。如果未指定,它将根据当前平台运行。

TextField 可控制的字段太多了,我们先来一个最简单的输入框,就一行代码。

TextField()

Flutter基础Widget使用----动画图解输入框

1.1 使用 InputDecoration

在 TextField 周围显示的装饰。默认情况下,在文本字段下绘制一条水平线,但可以配置为显示图标,标签,提示文本和错误文本。属性非常多,有兴趣的可以逐个研究一番,我就不再多谈。

  const InputDecoration({
    this.icon,
    this.labelText,
    this.labelStyle,
    this.helperText,
    this.helperStyle,
    this.hintText,
    this.hintStyle,
    this.hintMaxLines,
    this.errorText,
    this.errorStyle,
    this.errorMaxLines,
    this.hasFloatingPlaceholder = true,
    this.isDense,
    this.contentPadding,
    this.prefixIcon,
    this.prefix,
    this.prefixText,
    this.prefixStyle,
    this.suffixIcon,
    this.suffix,
    this.suffixText,
    this.suffixStyle,
    this.counter,
    this.counterText,
    this.counterStyle,
    this.filled,
    this.fillColor,
    this.focusColor,
    this.hoverColor,
    this.errorBorder,
    this.focusedBorder,
    this.focusedErrorBorder,
    this.disabledBorder,
    this.enabledBorder,
    this.border,
    this.enabled = true,
    this.semanticCounterText,
    this.alignLabelWithHint,
  }) : assert(enabled != null),

下面实现一个简易登陆输入界面。

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Home Page"),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            TextField(
              autofocus: true,
              decoration: InputDecoration(
                  labelText: "用户名",
                  hintText: "请输入用户名",
                  prefixIcon: Icon(Icons.person)),
            ),
            TextField(
              decoration: InputDecoration(
                  labelText: "密  码",
                  hintText: "请输入密码",
                  prefixIcon: Icon(Icons.lock)),
              obscureText: true,
            ),
          ],
        ));
  }
}

Flutter基础Widget使用----动画图解输入框

1.2 使用 textInputAction

我们知道 textInputAction 用于控制键盘的操作按钮的类型。具体看一下如何影响键盘上按钮的外观。

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Home Page"),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            TextField(
                autofocus: true,
                decoration: InputDecoration(
                    labelText: "百度一下",
                    hintText: "请输入你要查询的内容",
                    prefixIcon: Icon(Icons.search)),
                textInputAction: TextInputAction.search),
            TextField(
              decoration: InputDecoration(
                labelText: "对照组",
              ),
            )
          ],
        ));
  }
}

Flutter基础Widget使用----动画图解输入框

1.3 使用 controller

只要设置了controller,获取 TextField 非常容易。

class _MyHomePageState extends State<MyHomePage> {
  TextEditingController _searchController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Home Page"),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            TextField(
              autofocus: true,
              decoration: InputDecoration(
                  labelText: "百度一下",
                  hintText: "请输入你要查询的内容",
                  prefixIcon: Icon(Icons.search)),
              textInputAction: TextInputAction.search,
              controller: _searchController,
            ),
            RaisedButton(
              onPressed: () {
                setState(() {});
              },
              child: Text("获取TextField内容"),
            ),
            Text(_searchController.text),
          ],
        ));
  }
}

Flutter基础Widget使用----动画图解输入框

1.4 使用 focusNode

焦点可以通过 FocusNode 和 FocusScopeNode 来控制,默认情况下,焦点由 FocusScope 来管理,它代表焦点控制范围,可以在这个范围内可以通过 FocusScopeNode 在输入框之间移动焦点、设置默认焦点等。我们可以通过 FocusScope.of(context) 来获取 Widget 树中默认的 FocusScopeNode。

下面定义了三个输入框,焦点在它们三个之间,点击焦点移动按钮时候从上到下移动焦点。

class _MyHomePageState extends State<MyHomePage> {
  FocusNode focusNode1 = new FocusNode();
  FocusNode focusNode2 = new FocusNode();
  FocusNode focusNode3 = new FocusNode();

  FocusScopeNode focusScopeNode;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Home Page"),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            TextField(
              autofocus: true,
              focusNode: focusNode1,
              decoration: InputDecoration(
                labelText: "输入1",
              ),
            ),
            TextField(
              focusNode: focusNode2,
              decoration: InputDecoration(
                labelText: "输入2",
              ),
            ),
            TextField(
              focusNode: focusNode3,
              decoration: InputDecoration(
                labelText: "输入3",
              ),
            ),
            RaisedButton(
              onPressed: () {
                setState(() {
                  if (null == focusScopeNode) {
                    focusScopeNode = FocusScope.of(context);
                  }

                  if (focusNode1.hasFocus) {
                    focusScopeNode.requestFocus(focusNode2);
                  } else if (focusNode2.hasFocus) {
                    focusScopeNode.requestFocus(focusNode3);
                  } else if (focusNode3.hasFocus) {
                    focusScopeNode.requestFocus(focusNode1);
                  } else {
                    focusScopeNode.requestFocus(focusNode1);
                  }
                });
              },
              child: Text("焦点移动"),
            ),
          ],
        ));
  }
}

Flutter基础Widget使用----动画图解输入框

二、Form

Flutter提供了一个 Form 组件,它可以对输入框进行分组,然后进行一些统一操作,如输入内容校验、输入框重置以及输入内容保存。当需要提交很多字段内容的时候就派上了用场。

  const Form({
    Key key,
    @required this.child,
    this.autovalidate = false,
    this.onWillPop,
    this.onChanged,
  })

[child] 参数不能为 null。

autovalidate ---- 是否自动校验输入内容;当为 true 时,每一个子 FormField 内容发生变化时都会自动校验合法性,并直接显示错误信息。否则,需要通过调用 FormState.validate() 来手动校验。

onWillPop ---- 决定 Form 所在的路由是否可以直接返回(如点击返回按钮),该回调返回一个 Future 对象,如果 Future 的最终结果是 false,则当前路由不会返回;如果为 true,则会返回到上一个路由。此属性通常用于拦截返回按钮。

onChanged ---- Form 的任意一个子 FormField 内容发生变化时会触发此回调。

2.1 FormField

Form 的子孙元素必须是 FormField 类型,FormField 是一个抽象类。

  const FormField({
    Key key,
    @required this.builder,
    this.onSaved,
    this.validator,
    this.initialValue,
    this.autovalidate = false,
    this.enabled = true,
  }) 

这些属性基本上都是自解释的。

onSaved ---- 保存回调。

validator ---- 验证回调。

initialValue ---- 初始值。

autovalidate ---- 是否自动校验。

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

  TextFormField({
    Key key,
    this.controller,
    String initialValue,
    FocusNode focusNode,
    InputDecoration decoration = const InputDecoration(),
    TextInputType keyboardType,
    TextCapitalization textCapitalization = TextCapitalization.none,
    TextInputAction textInputAction,
    TextStyle style,
    StrutStyle strutStyle,
    TextDirection textDirection,
    TextAlign textAlign = TextAlign.start,
    bool autofocus = false,
    bool readOnly = false,
    bool showCursor,
    bool obscureText = false,
    bool autocorrect = true,
    bool autovalidate = false,
    bool maxLengthEnforced = true,
    int maxLines = 1,
    int minLines,
    bool expands = false,
    int maxLength,
    VoidCallback onEditingComplete,
    ValueChanged<String> onFieldSubmitted,
    FormFieldSetter<String> onSaved,
    FormFieldValidator<String> validator,
    List<TextInputFormatter> inputFormatters,
    bool enabled = true,
    double cursorWidth = 2.0,
    Radius cursorRadius,
    Color cursorColor,
    Brightness keyboardAppearance,
    EdgeInsets scrollPadding = const EdgeInsets.all(20.0),
    bool enableInteractiveSelection = true,
    InputCounterWidgetBuilder buildCounter,
  })

2.2 FormState

FormState 是与 [Form] Widget 关联的状态类。[FormState] 对象可用于 [save],[reset] 和 [validate] 作为关联 [Form] 的子孙的每个 [FormField]。

FormState.validate():调用此方法后,会调用 Form 子孙 FormField 的 validate 回调,如果有一个校验失败,则返回 false,所有校验失败项都会返回用户返回的错误提示。

FormState.save():调用此方法后,会调用 Form 子孙 FormField 的 save 回调,用于保存表单内容。

FormState.reset():调用此方法后,会将子孙 FormField 的内容清空。

下面是一个实例。

class FormTestRoute extends StatefulWidget {
  @override
  _FormTestRouteState createState() => new _FormTestRouteState();
}

class _FormTestRouteState extends State<FormTestRoute> {
  TextEditingController _nameController = new TextEditingController();
  TextEditingController _pwdController = new TextEditingController();
  GlobalKey _formKey = new GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Form Test"),
      ),
      body: Padding(
        padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 8.0),
        child: Form(
          key: _formKey,
          autovalidate: true,
          child: Column(
            children: <Widget>[
              TextFormField(
                  autofocus: true,
                  controller: _nameController,
                  decoration: InputDecoration(
                      labelText: "用户名",
                      hintText: "请输入用户名",
                      icon: Icon(Icons.person)),
                  validator: (v) {
                    return v.trim().length > 0 ? null : "用户名不能为空";
                  }),
              TextFormField(
                  controller: _pwdController,
                  decoration: InputDecoration(
                      labelText: "密  码",
                      hintText: "请输入密码",
                      icon: Icon(Icons.lock)),
                  obscureText: true,
                  validator: (v) {
                    return v.trim().length > 5 ? null : "密码不能少于6位";
                  }),
              // 登录按钮
              Padding(
                padding: const EdgeInsets.only(top: 10.0),
                child: Row(
                  children: <Widget>[
                    Expanded(
                      child: RaisedButton(
                        padding: EdgeInsets.all(6.0),
                        child: Text("登录"),
                        color: Theme.of(context).primaryColor,
                        textColor: Colors.white,
                        onPressed: () {
                          if ((_formKey.currentState as FormState).validate()) {
                            //验证通过提交数据
                            setState(() {});
                          }
                        },
                      ),
                    ),
                  ],
                ),
              ),
              Text("我的用户名=${_nameController.text},密码=${_pwdController.text}"),
            ],
          ),
        ),
      ),
    );
  }
}

Flutter基础Widget使用----动画图解输入框

相关标签: Flutter