Flutter自定义Widget实现自带删除键的TextField
程序员文章站
2022-05-30 17:36:53
...
在项目开发中,我们经常会用到输入框来输入一些信息,Android原生开发时使用的是EditText,在Flutter中则使用的是TextField。使用他们来实现类似选中获取焦点、输入值后显示删除键、清除已输入值等功能,则需要在布局中组合一些别的View(原生)或Widget(Flutter),并在代码中控制相关逻辑。
如果在一个页面中需要用到多个输入框,那么在布局文件以及代码逻辑中都将显得很冗余(因为要复制很多相似的代码),因此我们一般都会选择自定义组合View或Widget来实现这些功能,使得项目的布局和代码文件简洁、明了一些,同时也是为了使用方便。所以,笔者在学习Flutter时就在想,借着原生自定义组合View的思想,在Flutter中也实现一些类似的功能组件,也算是检验学习成果,毕竟理论与实践的结合才能掌握的更牢固!
首先看一下笔者实现的效果图哈!喜欢或者对自己有用,可以借鉴使用哦!
效果还不错,这也是笔者写这篇文章的初心吧,下面是笔者实现的自定义Widget-ClearTextField:
ClearTextField.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
///自带删除键的ClearTextField
typedef void ITextFieldCallBack(String content);
enum ITextInputType {
text,
multiline,
number,
phone,
datetime,
emailAddress,
url,
password
}
class ClearTextField extends StatefulWidget {
final ITextInputType keyboardType;
final int maxLines;
final int maxLength;
final String labelText;
final String hintText;
final TextStyle hintStyle;
final Icon deleteIcon;
final InputBorder inputBorder;
final Widget prefixIcon;
final TextStyle textStyle;
final ITextFieldCallBack fieldCallBack;
final FormFieldValidator<String> validator;
ClearTextField({
Key key,
ITextInputType keyboardType: ITextInputType.text,
this.maxLines = 1,
this.maxLength,
this.labelText,
this.hintText,
this.hintStyle,
this.deleteIcon,
this.inputBorder,
this.textStyle,
this.prefixIcon,
this.fieldCallBack,
this.validator,
}) : assert(maxLines == null || maxLines > 0),
assert(maxLength == null || maxLength > 0),
keyboardType = maxLines == 1 ? keyboardType : ITextInputType.multiline,
super(key: key);
@override
_ClearTextFieldState createState() {
return new _ClearTextFieldState();
}
}
class _ClearTextFieldState extends State<ClearTextField> {
String _inputText = "";
bool _hasDeleteIcon = false;
bool _hasFocus = false;
bool _isNumber = false;
bool _isPassword = false;
///输入类型
TextInputType _getTextInputType() {
switch (widget.keyboardType) {
case ITextInputType.text:
return TextInputType.text;
case ITextInputType.multiline:
return TextInputType.multiline;
case ITextInputType.number:
_isNumber = true;
return TextInputType.number;
case ITextInputType.phone:
_isNumber = true;
return TextInputType.phone;
case ITextInputType.datetime:
return TextInputType.datetime;
case ITextInputType.emailAddress:
return TextInputType.emailAddress;
case ITextInputType.url:
return TextInputType.url;
case ITextInputType.password:
_isPassword = true;
return TextInputType.text;
default:
return null;
}
}
///输入框焦点控制
FocusNode _focusNode = new FocusNode();
@override
void initState() {
super.initState();
_focusNode.addListener(_focusNodeListener);
}
Future<Null> _focusNodeListener() async {
if (_focusNode.hasFocus) {
setState(() {
_hasFocus = true;
});
} else {
setState(() {
_hasFocus = false;
});
}
}
///输入范围
List<TextInputFormatter> _getTextInputFormatter() {
return _isNumber
? <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly,
]
: null;
}
@override
Widget build(BuildContext context) {
TextEditingController _controller = new TextEditingController.fromValue(
TextEditingValue(
text: _inputText,
selection: new TextSelection.fromPosition(TextPosition(
affinity: TextAffinity.downstream,
offset: _inputText.length))));
TextField textField = new TextField(
focusNode: _focusNode,
controller: _controller,
decoration: InputDecoration(
hintStyle: widget.hintStyle,
counterStyle: TextStyle(color: Colors.white),
labelText: widget.labelText,
hintText: widget.hintText,
border: widget.inputBorder != null
? widget.inputBorder
: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide(color: Colors.green),
),
fillColor: Colors.transparent,
filled: true,
prefixIcon: widget.prefixIcon,
suffixIcon: _hasDeleteIcon && _hasFocus
? new Container(
width: 20.0,
height: 20.0,
child: new IconButton(
alignment: Alignment.center,
padding: new EdgeInsets.all(0.0),
iconSize: 18.0,
icon: widget.deleteIcon != null
? widget.deleteIcon
: Icon(Icons.cancel),
onPressed: () {
setState(() {
_inputText = "";
_hasDeleteIcon = _inputText.isNotEmpty;
widget.fieldCallBack(_inputText);
});
},
),
)
: new Text(""),
),
onChanged: (str) {
setState(() {
_inputText = str;
_hasDeleteIcon = _inputText.isNotEmpty;
widget.fieldCallBack(_inputText);
});
},
onSubmitted: (str) {
widget.fieldCallBack(_inputText);
setState(() {
_hasFocus = false;
});
},
keyboardType: _getTextInputType(),
maxLength: widget.maxLength,
maxLines: widget.maxLines,
style: widget.textStyle,
obscureText: _isPassword,
inputFormatters: _getTextInputFormatter(),
);
return textField;
}
}
有读者可能会问如何使用呢?下面笔者给出使用该自定义Widget的demo代码:
main.dart
import 'package:first_flutter_app/widget/text/ClearTextField.dart';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: ClearTextFieldPage(title: 'Flutter Demo ClearTextField'),
);
}
}
class ClearTextFieldPage extends StatefulWidget {
ClearTextFieldPage({Key key, this.title}) : super(key: key);
final String title;
@override
_ClearTextFieldPageState createState() => _ClearTextFieldPageState();
}
class _ClearTextFieldPageState extends State<ClearTextFieldPage> {
String _phoneNumber;
String _authNumber;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
margin: new EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0),
child: ClearTextField(
keyboardType: ITextInputType.phone,
prefixIcon: Icon(Icons.phone_android),
labelText: '手机号码',
hintText: '请输入手机号',
hintStyle: TextStyle(color: Colors.grey),
textStyle: TextStyle(color: Colors.black),
fieldCallBack: (content) {
_phoneNumber = content;
print(_phoneNumber);
},
),
),
Container(
margin: new EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0),
child: ClearTextField(
keyboardType: ITextInputType.password,
prefixIcon: Icon(Icons.https),
labelText: '密码',
hintText: '请输入密码',
hintStyle: TextStyle(color: Colors.grey),
textStyle: TextStyle(color: Colors.black),
fieldCallBack: (content) {
_authNumber = content;
},
),
),
],
),
),
);
}
}
大家可以运行一下,自己感受一下是否好使;
如有可改进的地方,还望不吝赐教,大家多多沟通学习,我也是Flutter学习者…
上一篇: UGUI--自定义重写Button
下一篇: sublime配置编译C/C++