Flutter TextField UI 实例 —— 新手礼包

锦通  论坛元老 | 2024-11-7 21:09:31 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1015|帖子 1015|积分 3045


各人好,我是17。
新手礼包一共 3 篇文章,每篇都是描述尽量具体,实例解说,包会!


  • Flutter Row 实例 —— 新手礼包
  • Flutter TextField UI 实例 —— 新手礼包
  • Flutter TextField 交互实例 —— 新手礼包
本篇先容了 TextField UI 的常见写法,从TextField的尺寸,border,icon,文本到光标,无所不包!
TextField 的尺寸

默认情况下,TextField 的宽度尽量大,高度包罗所有内容并加上 padding。TextField 可以通过 constraints 定义自己的尺寸。
下面的代码规定了 TextField 最大宽度为 200。
  1. TextField(
  2.        decoration: InputDecoration(
  3.           constraints: BoxConstraints(maxWidth: 200),
  4. ));
复制代码
让 TextFiled 在高度上也尽量大,设置 expands: true,同时还必须设置 maxLines,minLines 为 null。
  1. TextField(
  2.       maxLines: null,
  3.       minLines: null,
  4.       expands: true,
  5.     );
复制代码
需要留意在高度上的束缚必须是有限的,否则报错。
  1. Column(
  2.       children: [
  3.           TextField(expands: true,)
  4.       ],
  5.     );
复制代码
这个例子实行会报错。办理办法看下面的代码:
  1. Column(
  2.    children: [
  3.      SizedBox(
  4.          height: 200,
  5.          child: TextField(
  6.            expands: true,
  7.            maxLines: null,
  8.            minLines: null,
  9.          )),
  10.      TextField(
  11.        decoration:
  12.            InputDecoration(constraints: BoxConstraints(maxHeight: 200)),
  13.        expands: true,
  14.        maxLines: null,
  15.        minLines: null,
  16.      ),
  17.      Expanded(
  18.          child: TextField(
  19.        expands: true,
  20.        maxLines: null,
  21.        minLines: null,
  22.      ))
  23.    ],
  24. );
复制代码
Column 中有三个 TextField,一个用 SizedBox 包起来,一个用 InputDecoration 自带的 constraints 限定,一个用 Expanded 包起来,都是可以的,都可以让 TextField 在高度上的束缚是有限的。
除了 SizedBox,很多 widget 都有修改束缚的能力,好比 Container,ConstrainedBox 等。
Expanded 的表明可以看这篇 Flutter 弹性布局的基石: Flex 和 Flexible。
默认展示

第一个示例给出全部代码,贴到 main.dart 就能运行。后面的只给出 TextField 相关。
  1. import 'package:flutter/material.dart';
  2. void main() => runApp(const MyApp());
  3. class MyApp extends StatelessWidget {
  4.   const MyApp({super.key});
  5.   @override
  6.   Widget build(BuildContext context) {
  7.     return MaterialApp(
  8.         home: Scaffold(
  9.             body: Center(child: SizedBox(width: 300, child: MyWidget()))));
  10.   }
  11. }
  12. class MyWidget extends StatefulWidget {
  13.   const MyWidget({super.key});
  14.   @override
  15.   State<MyWidget> createState() => _MyWidgetState();
  16. }
  17. class _MyWidgetState extends State<MyWidget> {
  18.   var controller = TextEditingController(text: "IAM17");
  19.   @override
  20.   void dispose() {
  21.     controller.dispose();
  22.     super.dispose();
  23.   }
  24.   @override
  25.   Widget build(BuildContext context) {
  26.     return Column(
  27.       mainAxisSize: MainAxisSize.min,
  28.       children: [
  29.         TextField(),
  30.         SizedBox(
  31.           height: 20,
  32.         ),
  33.         TextField(),
  34.       ],
  35.     );
  36.   }
  37. }
复制代码
  没加 Const 关键字,因为反复修改的时候大概得一会删,一会加。发布代码的时候还是应该加上的。
    controller 后面会用到
  用两个 TextField 是为了方便检察 Focus 的效果。上面的为 正常状态的 TextField,下面的为 focus 状态的 TextField。默认设置正常状态下的 TextField 是一条灰线,有焦点的时候酿成蓝色。接下来,我们把他酿成想要的样子。
去掉下面的横线

  1. TextField(  
  2.     decoration: InputDecoration(  
  3.         border: InputBorder.none,  
  4.     ),  
  5. ),
复制代码
下面的横线着实就是 border,去掉后,现在只剩下一个光标了。想怎样装扮可以用其它 widget,好比可以用 Container 包起来,自定义 border,也可以用 Row 包起来,加各种图标。这是一个方案,如果你对 TextField 不熟悉,可以如许做来快速完成任务,但实际上,TextField 直接就可以完成大多数装扮,还是用优先用 TextField 自带的装扮为好,因为如许可以少写很多代码。
实际上,在设置 border: InputBorder.none后还是有 padding 的。为了彻底消除 decoration 的影响,可以把它设置为 null。
  1. TextField(
  2.      decoration: null,
  3. );
复制代码
加边框

  1. TextField(
  2.       decoration: InputDecoration(
  3.         border: OutlineInputBorder(
  4.             gapPadding: 4,
  5.             borderSide: BorderSide(
  6.                 color: Colors.green, width: 2, style: BorderStyle.solid),
  7.             borderRadius: BorderRadius.circular(10)),
  8.       ),
  9.     )
复制代码
我们给 TextField 加上了宽度为 2,圆角为 10 的边框。


  • width 是用来定义边框的宽度的,可以用小数,好比 1.5
  • style 是线框的样式,目前只有一种可选,就是BorderStyle.solid
  • color 是线框的颜色
  • borderRadius 可以定线框的圆角。
  • gapPadding 定义 labelText 左右的 Padding。
前面几个都好理解,gapPadding 我再放一个图就明白了。
gapPadding:4 修改为 100 看下效果。
gapPadding 是作用于 LabelText 的,为 LabelText 的左右添加空缺。固然在视觉上好像是只给右边加了空缺,着实左边也加了,只是左边没那么长的线框可以减,看起来好像是少了一小段,着实左边的上边框已经完全减掉了。
label 也可以拆开写,效果是一样的。
  1. labelText:  'IAM17',
  2. labelStyle: TextStyle(color:Color(0xFFC45F84),fontSize: 24),
复制代码
大概你会想到,要用虚线边框怎么办,需要自定义 decration,本文就不睁开说了。
如果你已经运行了示例代码,会发现 width,color 没有生效?确实是没有生效,线框的颜色还是默认的灰色,宽度还是 1。
定义线框的颜色和宽度

定义线框的宽度和颜色不能用 border。InputDecoration 按状态还为我们准备了五种 border,下面示范的是最常用的两种,正常状态下的 enabledBorder,和 focus 状态下的 focusedBorder。
  1. TextField(
  2.        decoration: InputDecoration(
  3.          enabledBorder: OutlineInputBorder(
  4.            borderRadius: BorderRadius.circular(5),
  5.            borderSide: BorderSide(
  6.              color: Colors.green,
  7.              width: 1.0,
  8.            ),
  9.          ),
  10.          focusedBorder: OutlineInputBorder(
  11.            borderRadius: BorderRadius.circular(30),
  12.            borderSide: BorderSide(
  13.              color: Color(0xFFC45F84),
  14.              width: 2.0,
  15.            ),
  16.          ),
  17.        ),
  18.      )
复制代码
第三种是 disabledBorder,看效果需要 enabled: false 禁用 TextField。禁用后会展示灰色 border,无法 focus。
  1. TextField(
  2.     decoration: InputDecoration(
  3.       enabled: false,
  4.       disabledBorder: OutlineInputBorder(
  5.         borderRadius: BorderRadius.circular(5),
  6.         borderSide: BorderSide(
  7.           color: Colors.grey,
  8.           width: 1.0,
  9.         ),
  10.       ),   
  11.     ),
  12. );
复制代码
第四种第五种是 error 相关,errorBorder 与 focusedErrorBorder。 给 errorText 赋值,就会触发 TextField 的错误状态。
  1. TextField(
  2.      decoration: InputDecoration(
  3.        errorBorder: OutlineInputBorder(
  4.          borderSide: BorderSide(
  5.            color: Color.fromARGB(255, 157, 23, 13),
  6.            width: 1.0,
  7.          ),
  8.        ),
  9.        errorText: '出错了!',
  10.        focusedErrorBorder: OutlineInputBorder(
  11.          borderRadius: BorderRadius.circular(5),
  12.          borderSide: BorderSide(
  13.            color: Colors.red,
  14.            width: 2.0,
  15.          ),
  16.        ),
  17.      ),
  18.    )
复制代码
文本样式,配景色

  1. TextField(
  2.       controller: controller,
  3.       style: TextStyle(color: Color(0xFFC45F84), fontSize: 24),
  4.       decoration: InputDecoration(
  5.           filled: true, fillColor: Color.fromARGB(255, 192, 241, 218)));
复制代码
controller 在最开始的代码中已经给出来了var controller = TextEditingController(text: "IAM17"); 现在我们用 controller 表现初始文本。
filled 默认为 false,fillColor 无效,要设置配景色,需要设置 filled: true,然后再设置 fillColor。
正文文本的样式用 style。可以用 textAlign 控制文本的摆放。我们可以把文本摆放在中间。
  1. TextField(
  2.         textAlign: TextAlign.center,
  3.         controller: controller,
  4.         style: TextStyle(color: Color(0xFFC45F84), fontSize: 24),
  5.         decoration: InputDecoration(
  6.             filled: true, fillColor: Color.fromARGB(255, 192, 241, 218)))
  7.   ]));
复制代码
除了可以摆放在中间,还可以摆在末尾,一共有 5 个值可选,具体可以检察 TextAlign
不敷生动?用 icon 和 text 来装扮吧!

  1. TextField(
  2.        controller: controller,
  3.        style: TextStyle(color: Color(0xFFC45F84), fontSize: 24),
  4.        decoration: InputDecoration(
  5.          icon: Icon(Icons.search),
  6.          prefixIcon: Icon(Icons.account_box),
  7.          prefix: Text('你是谁?',
  8.              style: TextStyle(
  9.                  color: Color.fromARGB(255, 25, 73, 6), fontSize: 20)),
  10.          suffixIcon: Icon(Icons.star),
  11.          suffix: Text('我们见过的',
  12.              style: TextStyle(
  13.                  color: Color.fromARGB(255, 14, 92, 99), fontSize: 20)),
  14.        ))
复制代码
  内容有点多,把最外面的 Container 的宽度放大到 400。
  一共有五个位置用来装饰。最前面的是 icon,在 border 的外面。接下来是 prefixIcon,然后是正文,末了是 suffix 和 subffixIcon。
这个五个位置固然从名字上来看是 Icon 和 Text,但实际上只要是 Widget 都可以!但最好是用 Icon,Text,因为如果用其它 Widget,大概享受不到 Theme 的福利了。
prefix,suffix 也可以用两个字段替换。
  1. prefixText: '你是谁?',
  2. prefixStyle: TextStyle( color: Color.fromARGB(255, 25, 73, 6), fontSize: 20),
  3. suffixText: '我们见过的',
  4. suffixStyle: TextStyle( color: Color.fromARGB(255, 14, 92, 99), fontSize: 20),
复制代码
  扩写和缩写只能采取一种,同时存在会报错!
  自定义 Icon 的颜色

当前 Icon 的 color 都是默认的,怎样修改 Icon 的颜色呢?大概你第一时间想到如许修改:
  1. icon: Icon(Icons.search,color:Colors.green),
复制代码
你肯定很高兴,it work! 现在 TextField 的正常状态和 foucs 状态的颜色都是 green。那么,如果想让 TextField 的 focus 状态的 icon 颜色是赤色,怎么办?
思索中…
好像很棘手,着实 Flutter 已经为我们设计好了怎样修改 Icon 的颜色,用 Theme!
首先定义一个 MaterialStateColor。
  1. class IconColor extends MaterialStateColor {
  2.   const IconColor() : super(_defaultColor);
  3.   //绿色
  4.   static const int _defaultColor = 0xff00ff00;
  5.   //红色
  6.   static const int _focusColor = 0xffff0000;
  7.   @override
  8.   Color resolve(Set<MaterialState> states) {
  9.     if (states.contains(MaterialState.focused)) {
  10.       return const Color(_focusColor);
  11.     }
  12.     return const Color(_defaultColor);
  13.   }
  14. }
复制代码
然后加入到 Theme 中,我们需要修改一下之前的代码。
  1. MaterialApp(
  2.    theme: ThemeData(
  3.       inputDecorationTheme: InputDecorationTheme(
  4.          iconColor: IconColor()
  5.        ),),
  6.    home: Scaffold(
  7.        body: Center(child: SizedBox(width: 400, child: MyWidget()))));
复制代码
检察效果默认的时候 icon 是绿色的,focus 的时候是赤色的。
如果你以为定义一个类太贫苦,也可以用 resolveWith 方法
  1. MaterialApp(
  2.     theme: ThemeData(
  3.       inputDecorationTheme: InputDecorationTheme(iconColor:
  4.           MaterialStateColor.resolveWith((Set<MaterialState> states) {
  5.         if (states.contains(MaterialState.focused)) {
  6.           return Colors.red;
  7.         }
  8.         return Colors.green;
  9.       })),
  10.     ),
  11.     home: Scaffold(
  12.         body: Center(child: SizedBox(width: 300, child: MyWidget()))));
复制代码
前面说的 border, 也可以通过 Theme 设置。如许就不用每个 TextField 都定一遍了!
  1. inputDecorationTheme: InputDecorationTheme(
  2.          enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.green)),
  3.          focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.red))
  4. )
复制代码
inputDecorationTheme 可以设置很多内容。Theme 相当于是 css 中的样式表。Theme 如果写在 MaterialApp 中,就相当于是全局样式表了,写在其它地方相当于局部样式表。子级的 Theme 的优先级大于父级的 Theme。写在 Widget 里的相当于 Style,优先级最高。
isDense

上面是默认 isDense:false 的效果,下面是 isDense:true 的效果,就是icon变小了一些。
  1. InputDecoration(
  2.      isDense: true,
  3.      icon: Icon(Icons.search),
  4.      prefixIcon: Icon(Icons.account_box),
  5.      prefix: Text('你是谁?',
  6.          style: TextStyle(
  7.              color: Color.fromARGB(255, 25, 73, 6), fontSize: 20)),
  8.      suffixIcon: Icon(Icons.star),
  9.      suffix: Text('我们见过的',
  10.          style: TextStyle(
  11.              color: Color.fromARGB(255, 14, 92, 99), fontSize: 20)),
  12.    );
复制代码
hint text 与 helper text

灰色的是 hintText,和 html 中 placeholder 差不多。绿色的是 helper Text,表现在左下角。
  1. TextField(
  2.    decoration: InputDecoration(
  3.      hintText: 'IAM17',
  4.      hintStyle: TextStyle(color: Colors.black54),
  5.      hintMaxLines: 1,
  6.      helperText: '我们见过的',
  7.      helperStyle: TextStyle(color: Color.fromARGB(255, 52, 116, 7)),
  8.      helperMaxLines: 1,
  9.    ))
复制代码
已经包罗 hint text 与 helper text 的所有属性了,比力好理解,就不再表明了。要留意的一点是:focus 对这两个 text 的样式没有影响。error 状态 hint text 没有变革,helper text 被 errorText 取代。
label text

同时有 label text 和 hint text 的时候,正常状态下会优先表现 labelText。在 focus 状态下,labelText 缩小到左上角,hint text 表现出来。
label text 远没有这么简单,除 labelText,labelStyle,还有几个属性需要相识。
floatingLabelStyle 定义 focus 状态下 label 表现在左上角的样式。正常状态下 label text 的颜色用 labelStyle 设置为灰色,浮到左上角后可以用 floatingLabelStyle 设置为绿色。
  1. TextField(
  2.     decoration: InputDecoration(
  3.       labelText: '你是谁',
  4.       labelStyle: TextStyle(color: Colors.grey),
  5.       floatingLabelStyle: TextStyle(color: Colors.green),
  6.     ))
  7. )
复制代码
floatingLabelAlignment 可以让左上角的 label 表现在中间。(只有 start 和 center 两个选项)
  1. TextField(
  2.    decoration: InputDecoration(
  3.      labelText: '你是谁',
  4.      labelStyle: TextStyle(color: Color.fromARGB(255, 194, 52, 101)),
  5.      floatingLabelStyle: TextStyle(color: Colors.blue),
  6.      floatingLabelAlignment: FloatingLabelAlignment.center
  7.    ));
复制代码
floatingLabelBehavior 控制 label 的举动,有三个选项


  • FloatingLabelBehavior.auto 默认。正常状态覆盖 hint,focus 状态上浮。
  • FloatingLabelBehavior.always 正常状态 和 focus 状态 都上浮。hint 正常表现。
  • FloatingLabelBehavior.never 正常状态覆盖 hint,focus 状态不上浮。这时就和 hint 并不多了,唯一差别的是 focus 的时候 hint 不消失,label 消失。
padding

默认情况下,在正文的附近是有 padding 的。
contentPadding: EdgeInsets.zero 可以去掉左右的 padding。
  1. decoration: InputDecoration(
  2.     contentPadding: EdgeInsets.zero,
  3.     filled: true,
  4.     fillColor: Color.fromARGB(255, 192, 241, 218)))
复制代码
去掉上下的 padding 要用到一个属性,isCollapsed可以把上下左右的 padding 都去掉。
  1. InputDecoration(
  2.     isCollapsed: true,
  3.     filled: true,
  4.     fillColor: Color.fromARGB(255, 192, 241, 218))
复制代码
也可以用InputDecoration.collapsed,但要求必须指定 hintText,不允许再指定 labelText,errorText,icon。
  1. InputDecoration.collapsed(
  2.    hintText: "你是谁",
  3.    filled: true,
  4.    fillColor: Color.fromARGB(255, 192, 241, 218))
复制代码
直接用 isCollapsed: true,可以指定 labelText,errorText,icon,但 UI 上大概不大理想,所以如果想去掉所有 padding,优先用 InputDecoration.collapsed。
自定义光标

可以自定义光标的宽度,radius,和颜色。
  1. TextField(
  2.      cursorWidth: 16.0,
  3.      cursorRadius: Radius.circular(18.0),
  4.      cursorColor: Color(0xFFC45F84),
  5.    ),
复制代码
Flutter TextField UI 常见写法到这里就竣事了,谢谢观看。
欢迎观看下一篇 Flutter TextField 交互实例 —— 新手礼包

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

锦通

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表