Flutter基础组件<输入框TextField>

Flutter入门笔记系列文章部分内容来源于《Flutter 实战》,如有侵权请联系删除!

Material组件库中为我们提供了输入框组件TextField。不管是Web端还是移动端开发,输入框都是最常用的组件之一,因此掌握输入框的使用显得尤为重要。

一、属性介绍

TextField属性比较多,本文只介绍其中比较常用的属性,更多属性请查阅SDK或官方文档。

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.enableSuggestions = 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,
})
  • controller:编辑框的控制器,通过它可以设置/获取编辑框的内容、选择编辑内容、监听编辑文本改变事件。大多数情况下我们都需要显式提供一个controller来与文本框交互。如果没有提供controller,则TextField内部会自动创建一个。

  • focusNode:用于控制TextField是否占有当前键盘的输入焦点。它是我们和键盘交互的一个句柄(handle)。

  • InputDecoration:用于控制TextField的外观显示,如提示文本、背景颜色、边框等。

  • keyboardType:用于设置该输入框默认的键盘输入类型,取值如下:

TextInputType枚举值 含义
text 文本输入键盘
multiline 多行文本,需和maxLines配合使用(设为null或大于1)
number 数字,会弹出数字键盘
phone 优化后的电话号码输入键盘;会弹出数字键盘并显示“* #”
datetime 优化后的日期输入键盘;Android上会显示“: -”
emailAddress 优化后的电子邮件地址;会显示“@ .”
url 优化后的url输入键盘; 会显示“/ .”
  • textInputAction:键盘动作按钮图标(即回车键位图标),它是一个枚举值,有多个可选值,全部的取值列表读者可以查看API文档,下面是当值为TextInputAction.search时,原生Android系统下键盘样式如图3-24所示:

    图3-24
  • style:正在编辑的文本样式。

  • textAlign: 输入框内编辑文本在水平方向的对齐方式。

  • autofocus: 是否自动获取焦点。

  • obscureText:是否隐藏正在编辑的文本,如用于输入密码的场景等,文本内容会用“•”替换。

  • maxLines:输入框的最大行数,默认为1;如果为null,则无行数限制。

  • maxLengthmaxLengthEnforcedmaxLength代表输入框文本的最大长度,设置后输入框右下角会显示输入的文本计数。maxLengthEnforced决定当输入文本长度超过maxLength时是否阻止输入,为true时会阻止输入,为false时不会阻止输入但输入框会变红。

  • onChange:输入框内容改变时的回调函数;注:内容改变事件也可以通过controller来监听。

  • onEditingCompleteonSubmitted:这两个回调都是在输入框输入完成时触发,比如按了键盘的完成键(对号图标)或搜索键(🔍图标)。不同的是两个回调签名不同,onSubmitted回调是ValueChanged<String>类型,它接收当前输入内容做为参数,而onEditingComplete不接收参数。

  • inputFormatters:用于指定输入格式;当用户输入内容改变时,会根据指定的格式来校验。

  • enable:如果为false,则输入框会被禁用,禁用状态不接收输入和事件,同时显示禁用态样式(在其decoration中定义)。

  • cursorWidthcursorRadiuscursorColor:这三个属性是用于自定义输入框光标宽度、圆角和颜色的。

二、登录示例:手机号+密码

1、编写布局代码

TextField(
  keyboardType: TextInputType.phone,
  maxLines: 1,
  autofocus: false,
  cursorColor: Colors.blue,
  maxLength: 11,
  maxLengthEnforced: true,
  focusNode: phoneFocusNode,
  decoration: InputDecoration(
    hintText: "请输入手机号码",
    labelText: "手机号",
    prefixIcon: Icon(Icons.phone),
    // 未获得焦点下划线设为灰色
    enabledBorder: UnderlineInputBorder(
      borderSide: BorderSide(color: Colors.grey),
    ),
    //获得焦点下划线设为蓝色
    focusedBorder: UnderlineInputBorder(
      borderSide: BorderSide(color: Colors.blue),
    ),
  ),
),
TextField(
  keyboardType: TextInputType.text,
  obscureText: true,
  maxLines: 1,
  autofocus: false,
  cursorColor: Colors.blue,
  focusNode: passwordFocusNode,
  decoration: InputDecoration(
    hintText: "请输入密码",
    labelText: "密码",
    prefixIcon: Icon(Icons.vpn_key),
    // 未获得焦点下划线设为灰色
    enabledBorder: UnderlineInputBorder(
      borderSide: BorderSide(color: Colors.grey),
    ),
    //获得焦点下划线设为蓝色
    focusedBorder: UnderlineInputBorder(
      borderSide: BorderSide(color: Colors.blue),
    ),
  ),
),
Padding(
  padding: EdgeInsets.all(16),
  child: RaisedButton(
      child: Text("开始登录"),
      onPressed: () {
        //开始登录
      }),
)

运行效果


登录页面

2、获取输入内容

  • 使用onChanged监听文本变化

最简单直接的方法是使用TextFile的onChanged属性监听输入框文本变化,从而获取到手机号和密码。

TextField(
  ……
  onChanged: (text) {
       print("phone=$text");
  },
)
TextField(
  ……
  onChanged: (text) {
       print("password=$text");
  },
)

运行效果


onChanged监听文本
  • 使用controller监听文本变化

controller使用步骤如下:
创建TextEditingController -> 设置TextFile的controller属性controller: phoneController, -> 重写方法initState()监听文本变化。

class _MyHomePageState extends State<MyHomePage> {
  bool checkboxState = false; //CheckBox状态
  bool switchState = false; //Switch状态

  void _incrementCounter() {
    setState(() {
      // This call to setState tells the Flutter framework that something has
      // changed in this State, which causes it to rerun the build method below
      // so that the display can reflect the updated values. If we changed
      // _counter without calling setState(), then the build method would not be
      // called again, and so nothing would appear to happen.
      _counter++;
    });
  }

  TextEditingController phoneController = TextEditingController();
  TextEditingController passwordController = TextEditingController();

  @override
  initState(){
    //监听输入改变
    phoneController.addListener((){
      //通过controller获取输入框内容
      print("phone="+phoneController.text);
    });
    passwordController.addListener((){
    //通过controller获取输入框内容
      print("password="+passwordController.text);
    });
  }
  ……
}

设置TextField的controller属性

TextField(
  ……
  controller: phoneController,
)

运行效果


controller监听文本

以上两种方法都可以成功获取到用户输入的手机号和密码。两种方式相比,onChanged是专门用于监听文本变化,而controller的功能却多一些,除了能监听文本变化外,它还可以设置默认值、选择文本。因此我们应该根据实际需求选择最合适的方法

三、控制输入框焦点

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

在上面登录的例子中可以看到TextField中有一个属性focusNode,它的值是FocusNode。简单介绍一下FocusNode中几个比较常用的成员变量和方法:

  • hasFocus
    判断当前Node是否拥有输入焦点
  • nextFocus()
    焦点移动到下一个FocusNode
  • previousFocus()
    焦点移动到上一个FocusNode
  • requestFocus([FocusNode node])
    指定某个FocusNode获得焦点
  • unfocus({ bool focusPrevious = false })
    从具有主要焦点的FocusNode上删除焦点,并取消所有未完成的聚焦请求。
    如果[focusPrevious]为true,焦点将会被移至FocusScopeNode觉得最合适的节点。当然FocusScopeNode会根据使用[FocusScopeNode.setFirstFocus]设置为首先关注节点的节点的历史记录,判断出最合适的节点。
    这一段我翻译得可能不太准确,所有附上官方解释吧!
    if [focusPrevious] is true, then rather than losing all focus, the focus will be moved to the node that the [enclosingScope] thinks should have it, based on its history of nodes that were set as first focus on it using [FocusScopeNode.setFirstFocus].
  • addListener(VoidCallback listener)
    FocusNode继承自ChangeNotifier,可以监听焦点的改变事件
// 创建 focusNode   
FocusNode focusNode = new FocusNode();

// focusNode绑定输入框   
TextField(focusNode: focusNode);

// 监听焦点变化    
focusNode.addListener((){
   print(focusNode.hasFocus);
});

获得焦点时focusNode.hasFocus值为true,失去焦点时为false。

四、自定义输入框样式

我们可以通过decoration属性来定义输入框样式:

TextField(
  decoration: InputDecoration(
    //在这里定义样式的属性
    ……
  )
)

InputDecoration属性比较多,我们通过几个简单的例子来介绍它们。

1、下划线

下面是与下划线有关的属性

属性 InputDecoration持有焦点 InputDecoration显示errorText
errorBorder NO YES
focusedBorder YES NO
focusedErrorBorder YES YES
属性 InputDecoration可用 InputDecoration显示errorText
disabledBorder NO NO
enabledBorder YES NO

例子:获取焦点时下划线为蓝色,失去焦点下划线为灰色

TextField(
  keyboardType: TextInputType.phone,
  maxLines: 1,
  autofocus: false,
  cursorColor: Colors.blue,
  textInputAction: TextInputAction.next,
  onSubmitted: (value) {
    print("onSubmitted$value");
    phoneFocusNode.nextFocus();
  },
  maxLength: 11,
  maxLengthEnforced: true,
  focusNode: phoneFocusNode,
//              onChanged: (text) {
//                print("phone=$text");
//              },
  controller: phoneController,
  decoration: InputDecoration(
    hintText: "请输入手机号码",
    labelText: "手机号",
    prefixIcon: Icon(Icons.phone),
    // 未获得焦点下划线设为灰色
    enabledBorder: UnderlineInputBorder(
      borderSide: BorderSide(color: Colors.grey),
    ),
    //获得焦点下划线设为蓝色
    focusedBorder: UnderlineInputBorder(
      borderSide: BorderSide(color: Colors.blue),
    ),
  ),
),

运行效果


获得焦点

失去焦点

2、其他属性

InputDecoration还有很多其他的属性,下图所示为比较常用的一些属性,更多属性请查阅文档:


其他属性
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容