csdn博客文章NO.2
前言:
今天带来的是登录框业务处理的完结篇,看不懂的一定不要慌,一点一点的研究,做好个例拆分。看不明白的,不是你笨拙,而是有些地方你不知道是什么,可能见都没有见过,所有慢慢熟悉各个组件的功能。这将会成为你手中的武器。
提示:以下是本篇文章正文内容,下面案例可供手敲
一、首先输入手机号的表单要做到那几点?
- 获得焦点的时候,表单的边框和右边的icon要变颜色
- 限制输入,长度必须是11位,必须是整数值类型
- 少位数提交不了,用提示框提示
第一点(这个框和密码框通用):
/*
* WhitelistingTextInputFormatter.digitsOnly //只允许输入数字
* LengthLimitingTextInputFormatter(20) //限制长度
*/
class MyInput extends StatefulWidget{
//这几个是调整距离的
double left;
double right;
double bottom;
double top;
double all;
//输入框里面的提示文字
String text;
//icon图标
IconData icon;
//是否是密码框
bool type;
//一开始的颜色,也就是点击时的颜色
Color initColor ;
//是否一开始就获取焦点
bool isFocus;
//长度大于length才返回,11为手机号,那么length就要等于10
int length;
//限制用户输入的条件数组
List<TextInputFormatter> inputFormatters;
//回调函数
ValueChanged<String> onChanged;
MyInput({
this.inputFormatters,
this.all = 0,
this.top = 0,
this.bottom = 0,
this.right = 28,
this.left = 28,
this.icon = Icons.check,
this.text = "账号",
this.type = false,
this.onChanged,
this.isFocus = false,
this.length = 11,
this.initColor,
});
State<StatefulWidget> createState() {
return MyInputState();
}
}
class MyInputState extends State<MyInput>{
//创建焦点
FocusNode focusNode = FocusNode();
//做个标记
bool flag = false;
@override
void initState() {
//做个标记,这个输入框是和密码框通用的
flag = widget.type;
if(!widget.isFocus){
widget.initColor = Color(0xff5D5D62);
}
//焦点监听
focusNode.addListener(() {
//获得焦点
if (focusNode.hasFocus) {
setState(() {
widget.initColor = MyColor.inputColor;
print('获得焦点........');
});
}
else {
setState(() {
widget.initColor = Color(0xff5D5D62);
print('失去焦点........');
//如果时密码框,失去焦点的时候要隐藏明文
if(widget.type){
setState(() {
this.flag = true;
});
}
});
}
},
);
}
@override
Widget build(BuildContext context) {
return
Container(
padding: widget.all!=0?EdgeInsets.all(widget.all):EdgeInsets.fromLTRB(widget.left, widget.top, widget.right, widget.bottom),
child: TextField(
inputFormatters:widget.inputFormatters==null?[
//默认允许输入字母数字一共11位数*
WhitelistingTextInputFormatter(RegExp("[a-zA-Z]|[0-9.]")),
LengthLimitingTextInputFormatter(11)
]:widget.inputFormatters,
autofocus: widget.isFocus,//自动获取焦点
focusNode: focusNode,//焦点监听
obscureText:this.flag,//是否时密码框
decoration: InputDecoration(
filled: true,//设置背景颜色
fillColor:MyColor.inputBcColor,
hintText: widget.text,//文本
border: InputBorder.none,//没有下划线
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
//自定义的颜色
color: MyColor.inputColor,
width: 1.5,
),
),
suffixIcon:
IconButton(
//右边显示的图标,SvgPicture是用来解析svg,比一些图片更灵活,然后是一个三元运算,结合密码框来的
icon:flag?SvgPicture.asset("assets/eye.svg",color: widget.initColor):
Icon(
widget.icon,
color: widget.initColor,
),
onPressed: (){
//类型时密码框的时候点击才有效果
if(widget.type){
setState(() {
this.flag = !this.flag;
});
}
},
)
),
//当输入手机号码的位数时才能返回
onChanged: (value){
if(value.toString().length > widget.minLength){
widget.onChanged(value);
}
}
),
);
}
}
二、验证码的输入框(第一篇有讲怎么使用)
1.引入库
//短信验证框
//flutter_verification_box: ^1.0.4
2.短信验证框
//短信验证功能
class VerificationCode extends StatelessWidget{
//调整位置的
double left;
double right;
double top;
double bottom;
//框的个数
int count
Function showCode = (String code){};
VerificationCode({
this.showCode,
this.left = 0,
this.right = 0,
this.bottom = 0,
this.top = 0
});
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.fromLTRB(this.left, this.top, this.right, this.bottom),
decoration: BoxDecoration(
color: MyColor.inputBcColor,
borderRadius: BorderRadius.circular(4),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.fromLTRB(ScreenUtil().setWidth(15), ScreenUtil().setHeight(20), 0, 20),
child: Text(
"手机验证码",style: TextStyle(fontSize: 16,fontWeight: FontWeight.w600,color:Color(0xff626F7A) ),
),
),
Container(
padding: EdgeInsets.only(left: 15,right: 15),
height: ScreenUtil().setHeight(50),
//这个被我改过源码,之前是要满足4个才返回,被修改之后是输入一个就返回一个
child: VerificationBox(
count: this.count,
itemWidget:ScreenUtil().setHeight(50),
showCursor: true,
cursorColor: MyColor.inputColor,
focusBorderColor: MyColor.inputColor,
textStyle: TextStyle(fontSize: ScreenUtil().setSp(28),fontWeight: FontWeight.w600),
onSubmitted: (code){
showCode(code);
},
),
)
],
),
);
}
}
}
3.按钮
- 验证码登录按钮比较特殊,一开始是灰色的,设置透明度
- 有计时器,会一直减少
- 输入框输入满了之后变成登录俩个字
- 如果计数器倒数完毕,没有输入,就显示重新获取
样式:
//手机号
class HintMessage extends StatelessWidget{
double top;
String mobile;
HintMessage({this.top,this.mobile});
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(top: this.top),
child: Center(
child: Text(
"已发送验证码到${this.mobile}",
style: TextStyle(
fontSize: 14,
color: MyColor.forbiddenColor
),
),
),
);
}
3.业务处理
- 验证成功通过路由传参,把电话号码过来(实际工作中验证码不会直接传,要后台验证)
class VerificationPage extends StatefulWidget {
//电话号码
String mobile;
//倒计时
int countdownTime;
VerificationPage({this.mobile,this.countdownTime});
@override
State<StatefulWidget> createState() {
return VerificationPageState();
}
}
class VerificationPageState extends State<VerificationPage>{
double opacity = 0.5;
String hint = "获取验证码";
int timeOut = 0;
Timer _timer;
bool isFill = false;
bool face = false;
int initTime;
@override
void initState() {
//计时器
initTime = widget.countdownTime;
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
setState(() {
widget.countdownTime = widget.countdownTime - 1;
});
});
super.initState();
}
@override
void dispose() {
_timer?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: ListView(
children: [
LoginTitle(),
//填写完之后返回的验证码
VerificationCode(
top: ScreenUtil().setHeight(25),
showCode: (code){
if(code.toString().length == 4){
Object pms = {"phone": widget.mobile, "code": code};
HttpController.fetch('xxxxxxxx', data: pms).then((result) {
if(result == "SUCCESS"){
face = true;
}
});
//输入完毕,登录按钮没有透明度,表示可以点击登录了
setState(() {
isFill = true;
opacity = 1;
hint = "登录";
});
}else{
//可以点击,不可以登录,重新获取验证码
setState(() {
isFill = false;
hint = "重新获取";
});
}
},
),
HintMessage(
top: 30,
mobile: widget.mobile,
),
MyLoginButton(
top: ScreenUtil().setHeight(30),
text:widget.countdownTime >0&&!isFill ? '${widget.countdownTime}后重新获取' : hint,
color: MyColor.inputColor,
opacity: this.opacity,
onTap: (){
if(isFill&&face){
//删除当前所有实例
RouteHelper.pushReplaceRoot( context, IndexPage());
}else if(isFill){
Fluttertoast.showToast(
msg: "验证码有误",
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.TOP,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0,
);
}
if(opacity == 1&& !isFill){
HttpController.fetch('/wx/sendBindCode', getpms: {'phone': widget.mobile}).then((data) {
setState(() {
widget.countdownTime = widget.countdownTime;
});
});
}
},
),
],
),
),
bottomNavigationBar: Permission(),
);
}
}
总结
有些地方会出错,其实这样更好,在你写的时候,可从这里找到你想要的
一些功能,我这里也仅仅是提供参考的作用。🤗🤗🤗🤗