TextField

[

](https://book.flutterchina.club/chapter3/input_and_form.html)

TextField的样式 decoration

  1. TextField(
  2. onChanged: (value) {
  3. //输入内容改变时的回调,value是变化后文本框里的内容
  4. debugPrint('input $value');
  5. },
  6. onSubmitted: (value) {
  7. //点击确定时的回调,value是文本框里所有的内容
  8. debugPrint('submit $value');
  9. },
  10. decoration: InputDecoration(
  11. icon: Icon(Icons.subject),
  12. labelText: 'Title', //输入框上方的title
  13. hintText: 'Enter Post Title', //placeText
  14. // border: InputBorder.none,//设置文本框的下边框无
  15. border: OutlineInputBorder(), //四周外边框
  16. fillColor: Colors.grey[400], //填充的背景色
  17. filled: true, //是否填充背景色
  18. ),
  19. );

监听文本变化

  • 使用TextEditingController监听文本字段变化 ```dart

class TextFieldDemo extends StatefulWidget { @override _TextFieldDemoState createState() => _TextFieldDemoState(); }

class _TextFieldDemoState extends State { final textEditingController = TextEditingController(); //创建文本框监听

@override void dispose() { // TODO: implement dispose textEditingController.dispose(); //释放textEditingController super.dispose(); }

@override void initState() { // TODO: implement initState super.initState(); textEditingController.text = ‘Hi’; textEditingController.addListener( () { debugPrint(‘input ${textEditingController.text}’); }, ); }

@override Widget build(BuildContext context) { return TextField( controller: textEditingController,

  1. onSubmitted: (value) {
  2. //点击确定时的回调,value是文本框里所有的内容
  3. debugPrint('submit $value');
  4. },
  5. decoration: InputDecoration(
  6. icon: Icon(Icons.subject),
  7. labelText: 'Title', //输入框上方的title
  8. hintText: 'Enter Post Title', //placeText
  9. // border: InputBorder.none,//设置文本框的下边框无
  10. border: OutlineInputBorder(), //四周外边框
  11. fillColor: Colors.grey[400], //填充的背景色
  12. filled: true, //是否填充背景色
  13. ),
  14. );

} }

  1. - 设置onChange回调
  2. ```dart
  3. TextField(
  4. autofocus: true,
  5. onChanged: (v) {
  6. print("onChange: $v");
  7. }
  8. )

控制焦点

  • 通过FocusNode和FocusScopeNode来控制 ```dart

class FocusTestRoute extends StatefulWidget { @override _FocusTestRouteState createState() => new _FocusTestRouteState(); }

class _FocusTestRouteState extends State { FocusNode focusNode1 = new FocusNode(); FocusNode focusNode2 = new FocusNode(); FocusScopeNode focusScopeNode;

@override Widget build(BuildContext context) { return Padding( padding: EdgeInsets.all(16.0), child: Column( children: [ TextField( autofocus: true, focusNode: focusNode1,//关联focusNode1 decoration: InputDecoration( labelText: “input1” ), ), TextField( focusNode: focusNode2,//关联focusNode2 decoration: InputDecoration( labelText: “input2” ), ), Builder(builder: (ctx) { return Column( children: [ RaisedButton( child: Text(“移动焦点”), onPressed: () { //将焦点从第一个TextField移到第二个TextField // 这是一种写法 FocusScope.of(context).requestFocus(focusNode2); // 这是第二种写法 if(null == focusScopeNode){ focusScopeNode = FocusScope.of(context); } focusScopeNode.requestFocus(focusNode2); }, ), RaisedButton( child: Text(“隐藏键盘”), onPressed: () { // 当所有编辑框都失去焦点时键盘就会收起
focusNode1.unfocus(); focusNode2.unfocus(); }, ), ], ); }, ), ], ), ); }

}

  1. - 监听焦点状态改变事件
  2. ```dart
  3. // 创建 focusNode
  4. FocusNode focusNode = new FocusNode();
  5. ...
  6. // focusNode绑定输入框
  7. TextField(focusNode: focusNode);
  8. ...
  9. // 监听焦点变化
  10. focusNode.addListener((){
  11. //获得焦点时focusNode.hasFocus值为true,失去焦点时为false。
  12. print(focusNode.hasFocus);
  13. });

Form 表单

  1. class RegisterForm extends StatefulWidget {
  2. @override
  3. _RegisterFormState createState() => _RegisterFormState();
  4. }
  5. class _RegisterFormState extends State<RegisterForm> {
  6. final registerFormKey = GlobalKey<FormState>(); //创建FormKey
  7. String username, password;
  8. bool autovalidate = false;
  9. void submitRegisterForm() {
  10. if (registerFormKey.currentState.validate()) {
  11. registerFormKey.currentState.save(); //调用onSave
  12. registerFormKey.currentState.validate(); //调用验证
  13. debugPrint('username : $username , password : $password');
  14. } else {
  15. setState(() {
  16. autovalidate = true;
  17. });
  18. }
  19. }
  20. String validatorUsername(value) {
  21. if (value.isEmpty) {
  22. return 'Username is required';
  23. }
  24. return null;
  25. }
  26. String validatorPassword(value) {
  27. if (value.isEmpty) {
  28. return 'Password is required';
  29. }
  30. return null;
  31. }
  32. @override
  33. Widget build(BuildContext context) {
  34. return Form(
  35. key: registerFormKey, //指定可以
  36. child: Column(
  37. children: <Widget>[
  38. TextFormField(
  39. decoration: InputDecoration(
  40. labelText: 'Username',
  41. helperText: '',
  42. ),
  43. onSaved: (value) {
  44. username = value; //获取TextField的值
  45. },
  46. validator: validatorUsername, //添加验证函数
  47. autovalidate: autovalidate,
  48. ),
  49. TextFormField(
  50. obscureText: true, //密码的圆点显示
  51. decoration: InputDecoration(
  52. labelText: 'Password',
  53. helperText: '',
  54. ),
  55. onSaved: (value) {
  56. password = value; //获取TextField的值
  57. },
  58. validator: validatorPassword, //添加验证函数
  59. autovalidate: autovalidate,
  60. ),
  61. SizedBox(
  62. height: 32.0,
  63. ),
  64. Container(
  65. width: double.infinity,
  66. child: RaisedButton(
  67. color: Theme.of(context).accentColor,
  68. child: Text('Register', style: TextStyle(color: Colors.white)),
  69. elevation: 0.0,
  70. onPressed: submitRegisterForm,
  71. ),
  72. )
  73. ],
  74. ),
  75. );
  76. }
  77. }

自定义案例

  1. import 'package:flutter/material.dart';
  2. ///主色调
  3. const MaterialColor primary = const MaterialColor(
  4. 0xfffb7299,
  5. const <int, Color>{50: const Color(0xffff9db5)},
  6. );
  7. ///登录输入框,自定义widget
  8. class LoginInput extends StatefulWidget {
  9. final String title;
  10. final String hint;
  11. final ValueChanged<String> onChanged;
  12. final ValueChanged<bool> focusChanged;
  13. final bool lineStretch;
  14. final bool obscureText;
  15. final TextInputType keyboardType;
  16. const LoginInput(this.title, this.hint,
  17. {Key key,
  18. this.onChanged,
  19. this.focusChanged,
  20. this.lineStretch = false,
  21. this.obscureText = false,
  22. this.keyboardType})
  23. : super(key: key);
  24. @override
  25. _LoginInputState createState() => _LoginInputState();
  26. }
  27. class _LoginInputState extends State<LoginInput> {
  28. final _focusNode = FocusNode();
  29. @override
  30. void initState() {
  31. super.initState();
  32. //是否获取光标的监听
  33. _focusNode.addListener(() {
  34. print("Has focus: ${_focusNode.hasFocus}");
  35. if (widget.focusChanged != null) {
  36. widget.focusChanged(_focusNode.hasFocus);
  37. }
  38. });
  39. }
  40. @override
  41. void dispose() {
  42. _focusNode.dispose();
  43. super.dispose();
  44. }
  45. @override
  46. Widget build(BuildContext context) {
  47. return Column(
  48. children: [
  49. Row(
  50. children: [
  51. Container(
  52. padding: EdgeInsets.only(left: 15),
  53. width: 100,
  54. child: Text(
  55. widget.title,
  56. style: TextStyle(fontSize: 16),
  57. ),
  58. ),
  59. _input()
  60. ],
  61. ),
  62. Padding(
  63. padding: EdgeInsets.only(left: !widget.lineStretch ? 15 : 0),
  64. child: Divider(
  65. height: 1,
  66. thickness: 0.5,
  67. ),
  68. )
  69. ],
  70. );
  71. }
  72. _input() {
  73. return Expanded(
  74. child: TextField(
  75. focusNode: _focusNode,
  76. onChanged: widget.onChanged,
  77. obscureText: widget.obscureText,
  78. keyboardType: widget.keyboardType,
  79. autofocus: !widget.obscureText,
  80. cursorColor: primary,
  81. style: TextStyle(
  82. fontSize: 16, color: Colors.black, fontWeight: FontWeight.w300),
  83. //输入框的样式
  84. decoration: InputDecoration(
  85. contentPadding: EdgeInsets.only(left: 20, right: 20),
  86. border: InputBorder.none,
  87. hintText: widget.hint ?? '',
  88. hintStyle: TextStyle(fontSize: 15, color: Colors.grey)),
  89. ));
  90. }
  91. }

复选框

Checkbox

  1. var checkbox = Checkbox(
  2. value: _checkBoxA,
  3. onChanged: (value) {
  4. setState(() {
  5. _checkBoxA = value;
  6. });
  7. },
  8. activeColor: Colors.black,//勾选状态的颜色,默认是主题下的Theme.of(context).accentColor
  9. );

CheckboxListTile

  1. var checkboxListTile = CheckboxListTile(
  2. value: _checkBoxA,
  3. onChanged: (value) {
  4. setState(() {
  5. _checkBoxA = value;
  6. });
  7. },
  8. title: Text('Checkbox Item A'),//标题文字
  9. subtitle: Text('Description'),//副标题
  10. secondary: Icon(Icons.bookmark),//显示的图标
  11. selected: _checkBoxA,//是否处于激活状态
  12. );

单选框

Radio

  1. class RadioDemo extends StatefulWidget {
  2. @override
  3. _RadioDemoState createState() => _RadioDemoState();
  4. }
  5. class _RadioDemoState extends State<RadioDemo> {
  6. int _radioGroupA = 0;
  7. void _handleRadioValueChanged(int value) {
  8. setState(() {
  9. _radioGroupA = value;
  10. });
  11. }
  12. @override
  13. Widget build(BuildContext context) {
  14. var radioDemo = Row(
  15. mainAxisAlignment: MainAxisAlignment.center,
  16. children: <Widget>[
  17. Radio(
  18. value: 0,
  19. groupValue: _radioGroupA,//权组值
  20. onChanged: _handleRadioValueChanged,
  21. activeColor: Colors.black,//选中的颜色
  22. ),
  23. Radio(
  24. value: 1,
  25. groupValue: _radioGroupA,//权组值
  26. onChanged: _handleRadioValueChanged,
  27. activeColor: Colors.black,//选中的颜色
  28. )
  29. ],
  30. );
  31. return Scaffold(
  32. appBar: AppBar(
  33. title: Text('RadioDemo'),
  34. elevation: 0.0,
  35. ),
  36. body: Container(
  37. padding: EdgeInsets.all(16.0),
  38. child: Column(
  39. mainAxisAlignment: MainAxisAlignment.center,
  40. children: <Widget>[
  41. radioDemo,
  42. ],
  43. ),
  44. ),
  45. );
  46. }
  47. }

RadioListTile

  1. Column(
  2. mainAxisAlignment: MainAxisAlignment.center,
  3. children: <Widget>[
  4. Text('RadioGroupValue:$_radioGroupA'),
  5. SizedBox(height: 32.0),
  6. RadioListTile(
  7. value: 0,
  8. groupValue: _radioGroupA,
  9. onChanged: _handleRadioValueChanged,
  10. title:Text('Option A') ,
  11. subtitle: Text('Description'),
  12. secondary: Icon(Icons.filter_1),//右侧图标
  13. selected: _radioGroupA == 0,
  14. ),
  15. RadioListTile(
  16. value: 1,
  17. groupValue: _radioGroupA,
  18. onChanged: _handleRadioValueChanged,
  19. title:Text('Option B') ,
  20. subtitle: Text('Description'),
  21. secondary: Icon(Icons.filter_2),//右侧图标
  22. selected: _radioGroupA == 1,
  23. ),
  24. ],
  25. ),

Switch和Slider

Switch

  1. import 'package:flutter/material.dart';
  2. class SwitchDemo extends StatefulWidget {
  3. @override
  4. _SwitchDemoState createState() => _SwitchDemoState();
  5. }
  6. class _SwitchDemoState extends State<SwitchDemo> {
  7. bool _switchA = false;
  8. @override
  9. Widget build(BuildContext context) {
  10. return Scaffold(
  11. appBar: AppBar(
  12. title: Text('SwitchDemo'),
  13. elevation: 0.0,
  14. ),
  15. body: Container(
  16. padding: EdgeInsets.all(16.0),
  17. child: Column(
  18. mainAxisAlignment: MainAxisAlignment.center,
  19. children: <Widget>[
  20. Text(_switchA ? '☺' :'😭',style: TextStyle(fontSize: 32.0)),
  21. Switch(
  22. value: _switchA,
  23. onChanged: (value) {
  24. setState(() {
  25. _switchA = value;
  26. });
  27. },
  28. )
  29. ],
  30. ),
  31. ),
  32. );
  33. }
  34. }

SwitchListTile

  1. SwitchListTile(
  2. value: _switchA,
  3. onChanged: (value) {
  4. setState(() {
  5. _switchA = value;
  6. });
  7. },
  8. title: Text('Switch Item A'),
  9. subtitle:Text('Description'),
  10. secondary: _switchA ? Icon(Icons.visibility):Icon(Icons.visibility_off),
  11. selected: _switchA,
  12. )

Slider

  1. Slider(
  2. value: _sliderA,
  3. onChanged: (value) {
  4. setState(() {
  5. _sliderA = value;
  6. });
  7. },
  8. min: 0.0,
  9. max: 10.0,
  10. divisions: 10,
  11. activeColor: Theme.of(context).accentColor,
  12. inactiveColor: Theme.of(context).accentColor.withOpacity(0.3),
  13. label: '${_sliderA.toInt()}',
  14. )