文章末尾有完整代码
TextField常用属性
- controller:设置一个TextEditingController对象作为文本输入控制器,可以通过该控制器获取或设置输入框中的文本内容
- onChanged:设置一个回调函数,当输入框的内容发生变化时会触发该函数。
- onSubmitted:设置一个回调函数,在用户提交文本后(按下回车键)会触发该函数。
- decoration:用于设置输入框的外观样式,包括边框、背景色等。
- keyboardType:指定键盘的类型,如文本、数字、电话号码等。
- obscureText:设置是否隐藏输入的文本,适用于密码输入场景。
- obscuringCharacter:自定义隐藏的展示样式;eg:"******" / "······"
- maxLength:限制输入的最大长度,有值后右下角就会有一个计数器(1/10)
- inputFormatters:输入校验,可限制输入文本长度
- focusNode:焦点
- enabled:输入框是否可用
- style:设置输入文本的样式
TextField(
focusNode: focusNode,
cursorColor: AppColors.getThemeYellow(context),
keyboardType: widget.keyboardType,
controller: widget.controller,
obscureText: _obscurePassword,
style: TextStyle(
fontSize: 16,
color: AppColors.getBlackOpacity_85(context),
letterSpacing: 0.5),
decoration: InputDecoration.collapsed(
hintText: widget.placeholder,
hintStyle: TextStyle(
fontSize: 16,
color: AppColors.getBlackOpacity_25(context),
fontWeight: FontWeight.normal),
),
inputFormatters: [
LengthLimitingTextInputFormatter(widget.maxLength) //限制长度
],
onChanged: (value) {
widget.onChange!(value);
})
InputDecoration是Flutter中的一个类,用于设置输入框的外观样式和提示文本等属性。它可以作为TextField、TextFormField等控件的decoration属性来使用。
InputDecoration.collapsed :不带边框的输入框
密码眼睛开关
点击开关按钮时
- 图标切换
- 输入框文本对应隐藏或显示
Widget _buildPasswordEyeIcon() {
return widget.usedInPassword
? InkWell(
child: Padding(
padding: const EdgeInsets.all(5),
child: _obscurePassword
? SvgPicture.asset(
R.ASSETS_SVG_IC_LOGIN_PWD_INVISIBLE_SVG,
colorFilter: ColorFilter.mode(
isDarkMode(context) ? Colors.white : Colors.black,
BlendMode.srcIn),
)
: SvgPicture.asset(
R.ASSETS_SVG_IC_LOGIN_PWD_VISIBLE_SVG,
colorFilter: ColorFilter.mode(
isDarkMode(context) ? Colors.white : Colors.black,
BlendMode.srcIn),
),
),
onTap: () => {setState(() => _obscurePassword = !_obscurePassword)},
)
: const SizedBox(width: 0);
}
清除文本
- 当输入框变化时判断
- 当光标变化时判断(获取焦点和失去焦点时,失去焦点时不展示清除按钮)
_obscurePassword = widget.usedInPassword;
//输入框变化时
widget.controller.addListener(() {
var isNotEmpty = widget.controller.text.isNotEmpty && focusNode.hasFocus;
setState(() {
_showClearIcon = isNotEmpty;
});
});
//光标变化时
focusNode.addListener(() {
var isNotEmpty = widget.controller.text.isNotEmpty && focusNode.hasFocus;
setState(() {
_showClearIcon = isNotEmpty;
});
});
Widget _buildClearIcon() {
return _showClearIcon
? InkWell(
child: Padding(
padding: const EdgeInsets.all(5),
child: SvgPicture.asset(
R.ASSETS_SVG_IC_REG_CLEAR_SVG,
colorFilter: ColorFilter.mode(
isDarkMode(context) ? Colors.white : Colors.black,
BlendMode.srcIn),
),
),
onTap: () => widget.controller.clear(),
)
: const SizedBox(width: 8.0);
}
完整输入框封装代码
- 左侧小图标
- 密码和非密码状态,密码开关
- 清除按钮
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:lib_flutter_why/config/app_theme.dart';
import '../../config/app_color.dart';
import '../../const/resource.dart';
class LoginTextField extends StatefulWidget {
final TextEditingController controller;
final TextInputType? keyboardType;
final String? placeholder;
final bool usedInPassword;
final int? maxLength;
final Function? onChange;
final Widget? icon;
final double width;
final EdgeInsets? edgeInsets;
final bool showLeftIcon;
const LoginTextField(
{Key? key,
required this.controller,
this.icon,
this.keyboardType,
this.placeholder,
this.usedInPassword = false,
this.maxLength,
this.onChange,
required this.width,
this.edgeInsets,
this.showLeftIcon = true})
: super(key: key);
@override
State<LoginTextField> createState() => _LoginTextFieldState();
}
class _LoginTextFieldState extends State<LoginTextField> {
var _showClearIcon = false;
late bool _obscurePassword;
FocusNode focusNode = FocusNode();
@override
void initState() {
super.initState();
_obscurePassword = widget.usedInPassword;
//输入框变化时
widget.controller.addListener(() {
var isNotEmpty = widget.controller.text.isNotEmpty && focusNode.hasFocus;
setState(() {
_showClearIcon = isNotEmpty;
});
});
//光标变化时
focusNode.addListener(() {
var isNotEmpty = widget.controller.text.isNotEmpty && focusNode.hasFocus;
setState(() {
_showClearIcon = isNotEmpty;
});
});
}
@override
Widget build(BuildContext context) {
return Container(
height: 52,
width: widget.width,
margin: widget.edgeInsets,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
flex: 0,
child: Visibility(
visible: widget.showLeftIcon,
child: Container(
margin: const EdgeInsets.only(right: 17),
child: widget.showLeftIcon ? widget.icon : null,
),
)),
Expanded(
flex: 1,
child: Container(
margin: const EdgeInsets.only(right: 17),
child: TextField(
focusNode: focusNode,
cursorColor: AppColors.getThemeYellow(context),
keyboardType: widget.keyboardType,
controller: widget.controller,
obscureText: _obscurePassword,
style: TextStyle(
fontSize: 16,
color: AppColors.getBlackOpacity_85(context),
letterSpacing: 0.5),
decoration: InputDecoration.collapsed(
hintText: widget.placeholder,
hintStyle: TextStyle(
fontSize: 16,
color: AppColors.getBlackOpacity_25(context),
fontWeight: FontWeight.normal),
),
inputFormatters: [
LengthLimitingTextInputFormatter(widget.maxLength) //限制长度
],
onChanged: (value) {
widget.onChange!(value);
}),
)),
_buildClearIcon(),
_buildPasswordEyeIcon(),
const SizedBox(
width: 10,
)
],
),
);
}
Widget _buildClearIcon() {
return _showClearIcon
? InkWell(
child: Padding(
padding: const EdgeInsets.all(5),
child: SvgPicture.asset(
R.ASSETS_SVG_IC_REG_CLEAR_SVG,
colorFilter: ColorFilter.mode(
isDarkMode(context) ? Colors.white : Colors.black,
BlendMode.srcIn),
),
),
onTap: () => widget.controller.clear(),
)
: const SizedBox(width: 8.0);
}
Widget _buildPasswordEyeIcon() {
return widget.usedInPassword
? InkWell(
child: Padding(
padding: const EdgeInsets.all(5),
child: _obscurePassword
? SvgPicture.asset(
R.ASSETS_SVG_IC_LOGIN_PWD_INVISIBLE_SVG,
colorFilter: ColorFilter.mode(
isDarkMode(context) ? Colors.white : Colors.black,
BlendMode.srcIn),
)
: SvgPicture.asset(
R.ASSETS_SVG_IC_LOGIN_PWD_VISIBLE_SVG,
colorFilter: ColorFilter.mode(
isDarkMode(context) ? Colors.white : Colors.black,
BlendMode.srcIn),
),
),
onTap: () => {setState(() => _obscurePassword = !_obscurePassword)},
)
: const SizedBox(width: 0);
}
}