Flutter 表单
表单 -- Switch
Switch
value:开关的值,一般与状态字段绑定
onChanged:开关状态变更时调用
activeColor:开关开启时的圆圈颜色
activeTrackColor:开关开启时的轨道颜色
inactiveThumbColor:开关关闭时的圆圈颜色
inactiveTrackColor:开关关闭时的轨道颜色
CupertinoSwitch(iOS 风格的开关)
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Switch'), ), body: const SwitchDemo(), ); } } class SwitchDemo extends StatefulWidget { const SwitchDemo({Key? key}) : super(key: key); @override State<SwitchDemo> createState() => _SwitchDemoState(); } class _SwitchDemoState extends State<SwitchDemo> { // Switch开关的选中状态 bool _switchValue = false; @override Widget build(BuildContext context) { return ListView( children: [ // Switch 简单用法 ListTile( leading: Switch( value: _switchValue, onChanged: (bool value) { setState(() { _switchValue = value; }); }, ), title: Text('基本用法:${_switchValue == true ? '选中' : '未选中'}'), ), // Switch 属性介绍 ListTile( leading: Switch( value: _switchValue, onChanged: (bool value) { setState(() { _switchValue = value; }); }, // 开关打开时圆圈的颜色 activeColor: Colors.green, // 开关打开时轨道的颜色 activeTrackColor: Colors.green[100], // 开关关闭时圆圈的颜色 inactiveThumbColor: Colors.yellow, // 开关关闭时轨道的颜色 inactiveTrackColor: Colors.yellow[100], ), title: Text('修改属性:${_switchValue == true ? '选中' : '未选中'}'), ), // iOS 风格的开关 ListTile( leading: CupertinoSwitch( value: _switchValue, onChanged: (bool value) { setState(() { _switchValue = value; }); }, // 开关圆圈的颜色 thumbColor: Colors.red, // 开关打开时轨道的颜色 activeColor: Colors.red[100], // 开关关闭时轨道的颜色 trackColor: Colors.yellow, ), title: Text('iOS 风格的开关:${_switchValue == true ? '选中' : '未选中'}'), ), ], ); } }
表单 -- Checkbox
Checkbox
value:复选框的值,取值共3个:true, false, null(tristate 取值为 true 时)
onChanged:复选框状态更改时调用
activeColor:选中时,复选框背景的颜色
checkColor:选中时,复选框中对号的颜色
CheckboxListTile
title:标题
subtitle:子标题
import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart' show timeDilation; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Checkbox Demo'), ), body: const CheckboxDemo(), ); } } class CheckboxDemo extends StatefulWidget { const CheckboxDemo({Key? key}) : super(key: key); @override State<CheckboxDemo> createState() => _CheckboxDemoState(); } class _CheckboxDemoState extends State<CheckboxDemo> { bool _apple = true; bool _pear = false; bool _banana = false; bool _wakeup = false; @override Widget build(BuildContext context) { return ListView( children: [ ListTile( leading: Checkbox( value: _apple, // 取值可能为空 onChanged: (bool? val) { setState(() { _apple = val!; }); }, ), title: Text('苹果,状态:$_apple'), ), ListTile( leading: Checkbox( value: _pear, // 取值可能为空 onChanged: (bool? val) { setState(() { _pear = val!; }); }, ), title: Text('大鸭梨,状态:$_pear'), ), ListTile( leading: Checkbox( value: _banana, // 取值可能为空 onChanged: (bool? val) { setState(() { _banana = val!; }); }, // 选中时,复选框的背景颜色 activeColor: Colors.yellow, // 选中时,钩子的颜色 checkColor: Colors.red, ), title: Text('香蕉,状态:$_banana'), ), // timeDilation 会让动画效果慢下来 CheckboxListTile( title: const Text('Animate Slowly'), value: timeDilation != 1.0, onChanged: (bool? value) { setState(() { timeDilation = value! ? 10.0 : 1.0; }); }, secondary: const Icon(Icons.hourglass_empty), ), CheckboxListTile( value: _wakeup, onChanged: (bool? val) { setState(() { _wakeup = val!; }); }, // 主标题 title: const Text('7:00'), // 子标题 subtitle: const Text('起床上学啦!'), // 图标 secondary: const Icon(Icons.alarm), // 选中时的背景色 activeColor: Colors.green, // 选中时钩子的颜色 checkColor: Colors.red, // 选中时,图标和文本也用 activeColor 重新渲染 selected: _wakeup, ), ], ); } }
表单 -- Radio
Radio(单选框)
value:开关的值,一般与状态字段绑定
onChanged:开关状态变更时调用
groupValue:选择组的值
RadioListTile(单选列表)
value:开关的值,一般与状态字段绑定
onChanged:开关状态变更时调用
groupValue:选择组的值
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Radio Demo'), ), body: const RadioDemo(), ); } } class RadioDemo extends StatefulWidget { const RadioDemo({Key? key}) : super(key: key); @override State<RadioDemo> createState() => _RadioDemoState(); } class _RadioDemoState extends State<RadioDemo> { dynamic gender; @override Widget build(BuildContext context) { return ListView( children: [ Row( children: [ const Text('男'), Radio( value: 1, groupValue: gender, onChanged: (value) { setState(() { gender = value; }); }, ), const Text('女'), Radio( value: 2, groupValue: gender, onChanged: (value) { setState(() { gender = value; }); }, ), ], ), RadioListTile( value: 1, groupValue: gender, onChanged: (value) { setState(() { gender = value; }); }, title: const Text('男'), subtitle: const Text('male'), secondary: const Icon(Icons.person), ), RadioListTile( value: 2, groupValue: gender, onChanged: (value) { setState(() { gender = value; }); }, title: const Text('女'), subtitle: const Text('female'), secondary: const Icon(Icons.person), // 选中的颜色 activeColor: Colors.yellow, // 选中时,文本和按钮会用 activeColor 渲染 selected: gender == 2, ), ], ); } }
表单 -- TextField
属性:
autofocus:是否获取焦点
keyboardType:键盘类型
obsureText:设置为密码框
decoration:样式修饰
onChanged:内容更改时自动调用 - value
labelText:标题
hintText:提示文字 - placeholder
maxLines:显示行数 - 文本域
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('TextField Demo'), ), body: const TextFieldDemo(), ); } } class TextFieldDemo extends StatefulWidget { const TextFieldDemo({Key? key}) : super(key: key); @override State<TextFieldDemo> createState() => _TextFieldDemoState(); } class _TextFieldDemoState extends State<TextFieldDemo> { String phone = ''; String password = ''; String description = ''; _register() { print('phone: $phone'); // phone: 12365412569 print('password: $password'); // phone: 12365412569 print('description: $description'); // description: srttg tutu edghh } @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(10), child: ListView( children: [ // 手机号 TextField( autofocus: true, keyboardType: TextInputType.phone, decoration: const InputDecoration( prefixIcon: Icon(Icons.mobile_screen_share), labelText: '手机号', hintText: '请输入手机号', hintStyle: TextStyle( color: Colors.pink, fontSize: 14, ), // 聚焦时边框的样式 focusedBorder: UnderlineInputBorder( borderSide: BorderSide( color: Colors.green, ), ), // 默认边框样式 enabledBorder: UnderlineInputBorder( borderSide: BorderSide( color: Colors.yellow, ), ), ), maxLength: 11, onChanged: (value) { setState(() { phone = value; }); }, ), // 密码 TextField( // 隐藏文本 obscureText: true, keyboardType: TextInputType.text, decoration: const InputDecoration( prefixIcon: Icon(Icons.code_outlined), labelText: '密码', hintText: '请输入密码', ), onChanged: (value) { setState(() { password = value; }); }, ), // 文本域 TextField( keyboardType: TextInputType.text, decoration: const InputDecoration( prefixIcon: Icon(Icons.person), labelText: '简介', hintText: '请简要介绍一下自己', ), maxLines: 3, onChanged: (value) { setState(() { description = value; }); }, ), // 按钮 Container( width: double.infinity, padding: const EdgeInsets.all(20), child: ElevatedButton( child: const Text('提交'), onPressed: () { _register(); }, ), ), ], ), ); } }
表单 -- 日历
CalendarDatePicker(日历选择器)
属性:
initialCalendarMode
DatePickerMode.day
DatePickerMode.year
showDatePicker(日期选择器)
属性:
initialDatePickerMode (year | day)
initialEntryMode (calendar | input)
showTimePicker(时间选择器)
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Calendar Demo'), ), body: const CalendarDemo(), ); } } class CalendarDemo extends StatefulWidget { const CalendarDemo({Key? key}) : super(key: key); @override State<CalendarDemo> createState() => _CalendarDemoState(); } class _CalendarDemoState extends State<CalendarDemo> { @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(15), child: ListView( children: [ _showDatePicker(context), _showDatePickerForYear(context), ], ), ); } // 日期选择器 ElevatedButton _showDatePicker(context) { return ElevatedButton( onPressed: () { showDatePicker( context: context, // 日期选择模式,取值为 day 或 year initialDatePickerMode: DatePickerMode.day, // 初始化选中日期 initialDate: DateTime.now(), // 开始日期 firstDate: DateTime(2022, 5), // 结束日期 lastDate: DateTime(2022, 12), // 日历弹框样式,默认:calendar initialEntryMode: DatePickerEntryMode.calendar, // 当前日期 currentDate: DateTime.now(), // 左上方提示 helpText: '日期选择器', // 取消按钮文案 cancelText: '取消', // 确认按钮文案 confirmText: '确定', // 格式错误提示 errorFormatText: 'Input format error', // 输入不在 first 与 last 之间日期提示 errorInvalidText: 'Out of date range', // 输入框上方提示 fieldLabelText: '请输入日期', // 输入框为空时内部提示 fieldHintText: '输入日期不能为空', // 是否为根导航器 useRootNavigator: true, // 设置不可选日期 selectableDayPredicate: (dateTime) { if (dateTime == DateTime(2022, 10, 1)) { return false; } return true; }); }, child: const Text('showDatePicker'), ); } // 年份选择器 ElevatedButton _showDatePickerForYear(context) { return ElevatedButton( onPressed: () { showDatePicker( context: context, // 初始化选中日期 initialDate: DateTime(2019, 1, 1), // 开始日期 firstDate: DateTime(2002), // 结束日期 lastDate: DateTime(2066), // 当前日期 currentDate: DateTime.now(), // 左上方提示 helpText: '年份选择器', // 取消按钮文案 cancelText: '取消', // 确认按钮文案 confirmText: '确认', ); }, child: const Text('showYearPicker'), ); } }
表单 -- Form
使用步骤
(1)、创建表单 Form,并以 GlobalKey 作为唯一性标识
(2)、添加带验证逻辑的 TextFormField 到 Form 中
(3)、创建按钮以验证和提交表单
Form(表单容器)
必填属性:
key: GlobalKey
child:子组件
创建表单唯一键:final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
验证表单:_formKey.currentState.validate();
提交表单:_formKey.currentState.save();
重置表单:_formKey.currentState.reset();
TextFormField(输入框)
与 TextField 的区别:必须在 Form 内使用 & 带有验证器
validator:验证器
obscureText:密码框
onSaved:
设定表单字段的值
在表单的 save() 方法之后执行
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Form Demo'), ), body: const FormStateDemo(), ); } } class FormStateDemo extends StatefulWidget { const FormStateDemo({Key? key}) : super(key: key); @override State<FormStateDemo> createState() => _FormStateDemoState(); } class _FormStateDemoState extends State<FormStateDemo> { final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); String _phone = ''; String _password = ''; @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(20), child: Column( children: [ Form( key: _formKey, child: Column( children: [ // 手机号 TextFormField( decoration: const InputDecoration( hintText: '手机号', ), // 校验 validator: (value) { print('手机号 value: $value'); RegExp reg = RegExp(r'^\d{11}$'); if (!reg.hasMatch(value!)) { print('error'); return '手机号码输入有误!'; } return null; }, // 设定表单字段的值 onSaved: (value) { print('_phone onSaved'); _phone = value!; }, ), // 密码 TextFormField( decoration: const InputDecoration( hintText: '密码', ), // 校验 validator: (value) { print('密码 value: $value'); return value!.length < 6 ? '密码有误!' : null; }, // 设定表单字段的值 onSaved: (value) { print('_password onSaved'); _password = value!; }, ), ], ), ), Row( children: [ Expanded( child: ElevatedButton( onPressed: () { if (_formKey.currentState!.validate()) { print('提交成功!'); print('_formKey.currentState!.save() Before'); // 提交表单 _formKey.currentState!.save(); print('_formKey.currentState!.save() After'); print('_phone: $_phone'); print('_password: $_password'); } }, child: const Text('提交'), ), ), const SizedBox( width: 20, ), Expanded( child: ElevatedButton( onPressed: () { _formKey.currentState!.reset(); }, child: const Text('重置'), ), ), ], ), ], ), ); } }