组件选择
- 有iOS风格的CupertinoTextField和Android风格的TextField两种;
- 从外观来看,还是CupertinoTextField好一些;
- CupertinoTextField还有自动出现的删除按钮,非常实用;
- 一开始我们选择的是CupertinoTextField,后来据说遇到三星手机输入框出现自动关闭的问题,所以我们换成了TextField;
封装想法
- 我们不需要外边框和错误提示信息什么的,所以外部套一个Container
- Container相关的margin,padding,宽,高,背景色,圆角等参数可以放出来,或者给个默认值。
- TextField专门做输入,前面,后面的图标等都不用,用一个Row组件套外层,可以完全自定义。
- TextField需要指定宽度,放在Row中,只要套一个Expanded组件就可以了。
- 文本样式,占位符及其样式,用的比较多,给个默认值;
- 通过监听FocusNode的方式实现删除按钮功能;
- 至于提交,变换,键盘类型等各种输入相关参数,直接透传就可以了
参考代码
class OneLineInputWidget extends StatefulWidget {
const OneLineInputWidget({
super.key,
this.placeholder,
this.placeholderStyle,
this.style,
this.controller,
this.onSubmitted,
this.textInputAction,
this.keyboardType,
this.textAlign = TextAlign.start,
this.enabled = true,
this.obscureText = false,
this.width,
this.radius = 0,
this.margin,
this.padding,
this.bgColor,
this.height,
this.focusNode,
this.showCursor = false,
this.defaultText,
this.onChanged,
this.inputFormatters,
});
final String? placeholder;
final TextStyle? placeholderStyle;
final TextStyle? style;
final TextEditingController? controller;
final ValueChanged<String>? onSubmitted;
final ValueChanged<String>? onChanged;
final TextInputAction? textInputAction;
final TextInputType? keyboardType;
final TextAlign textAlign;
final bool enabled;
final bool obscureText;
final double? width;
final double radius;
final EdgeInsetsGeometry? margin;
final EdgeInsetsGeometry? padding;
final Color? bgColor;
final double? height;
final FocusNode? focusNode;
final bool showCursor;
final String? defaultText;
final List<TextInputFormatter>? inputFormatters;
@override
State<OneLineInputWidget> createState() => _OneLineInputWidgetState();
}
class _OneLineInputWidgetState extends State<OneLineInputWidget> {
late FocusNode actualFocusNode;
late TextEditingController actualController;
bool isFocused = false;
@override
void initState() {
super.initState();
actualFocusNode = widget.focusNode ?? FocusNode();
actualController = widget.controller ?? TextEditingController();
if (widget.showCursor) {
Future.delayed(Duration.zero, () {
FocusScope.of(Get.context!).requestFocus(actualFocusNode);
});
}
if ((widget.defaultText != null) && (widget.defaultText!.isNotEmpty)) {
actualController.text = widget.defaultText!;
}
/// 监听焦点变化
actualFocusNode.addListener(() {
if (actualFocusNode.hasFocus) {
isFocused = true;
} else {
isFocused = false;
}
setState(() {});
});
}
@override
void dispose() {
if (widget.controller == null) {
actualController.dispose();
}
if (widget.focusNode == null) {
actualFocusNode.dispose();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
bool showSuffix = widget.enabled && isFocused;
return Container(
width: widget.width,
height: widget.height ?? 40.r,
margin: widget.margin,
padding: widget.padding,
decoration: BoxDecoration(
color: widget.bgColor,
borderRadius: BorderRadius.circular(widget.radius),
),
child: Row(
children: [
Expanded(
child: TextField(
controller: actualController,
decoration: InputDecoration(
hintText: widget.placeholder ?? "please_input".tr,
hintStyle: widget.placeholderStyle ?? StyleUtils.ts_99_12_400,
border: InputBorder.none,
suffixIcon: showSuffix
? GestureDetector(
onTap: () {
actualController.clear();
},
child: Icon(
Icons.clear_outlined,
color: ColorUtils.c_9a9a9a,
),
)
: null,
),
style: widget.style ?? StyleUtils.ts_33_13_500,
//键盘回车搜索
textInputAction: widget.textInputAction,
onSubmitted: widget.onSubmitted,
onChanged: widget.onChanged,
keyboardType: widget.keyboardType,
textAlign: widget.textAlign,
enabled: widget.enabled,
obscureText: widget.obscureText,
focusNode: actualFocusNode,
inputFormatters: widget.inputFormatters,
),
),
],
),
);
}
}