接下来要说的是登录界面要注意的一些问题。app的登录界面一般会有密码登录、验证码登录、忘记密码跟注册账号这几个模块,功能实现还是比较简单的,主要是一些细节的设计,因为我也不是专业做UI设计的,所以不会说怎样怎样设计才好看,主要还是说下功能实现的部分。
我在demo中主要是做了账号登录,验证码登录跟忘记密码三个功能。其实验证码登录、忘记密码、账号注册这三个功能模块实现的代码都是差不多的,而且功能还能复用,这个在下文会说明。
账号密码登录界面实现的逻辑主要是包括了1.本地验证账号密码的合法,2.提交到后台判断是否成功登录,是的话进入主界面。否则重新登录。
其中两个文本框都是用TextField来实现的,每个文本框分别用了装饰器来做了些提示的功能,下面码上部分代码
TextEditingController passwordController = new TextEditingController();
Widget PasswordField()
{
return new TextField(
textAlign: TextAlign.left,
style: new TextStyle(fontSize: 20),
controller:passwordController,
obscureText: isObscure,
//autovalidate: validataPassword,
//focusNode: passwordFocus,
onChanged: (text) => { setState(() => password = text); },
//validator: (value) => { return value.Trim().Length > 0 ? null : "密码不能为空"; },
decoration: new InputDecoration(
hintText: "请输入密码",
hintStyle: new TextStyle(color: Color.fromARGB(255, 221, 221, 221),fontSize:15),
suffixIcon: password == "" ? null :
new Container(child:new Row(
mainAxisSize: MainAxisSize.min,
children: PasswordIcon()))
)
);
}
List<Widget> PasswordIcon()
{
return new List<Widget> {
new GestureDetector(child: new Icon(isObscure?Icons.visibility_off:Icons.visibility),
onTap: () => { setState(()=> { isObscure=!isObscure; }); }),
new GestureDetector(child: new Icon(Icons.clear),onTap: () => { setState(()=> { passwordController.text = ""; }); })};
}
代码主要实现了密码框的实现,主要是包括了实现隐匿或者密码,清空密码,提示用户输入这些功能。和UGUI直接拖拽UI组件不一样的是,UIWidgets的所有组件都需要自己编写,虽然编写过程比较繁琐,但是自由度相当大,几乎可以编辑每一个组件的每一个属性,而且如果掌握其中的技巧的话,很多功能组件都能复用,从而且整出一套自定义的组件库。
登录按钮是用一个RaisedButton来实现的,会根据用户输入来改变颜色,主要是做登录验证。、
new Container(
height: 48,
constraints: new BoxConstraints(minWidth: float.PositiveInfinity, maxHeight: float.PositiveInfinity),
child: new RaisedButton(
shape:new RoundedRectangleBorder(borderRadius:BorderRadius.circular(5)),
color: password != "" && accountController.text != "" ? Colors.blue : Color.fromARGB(255, 85, 85, 85),
child: new Text("登录", style: new TextStyle(color: Color.white, fontSize: 15)),
onPressed: () => {
if (password == "" || account == "")
{
// ShowMessage("账号或密码不能为空");
}
else
{
Login(account, password);
}
})),
首先为了让用一个container作为RaisedButton的父节点,并且设置了子节点填充,这样就不用设置按钮大小,直接根据父节点来填充。同时用了shape来让按钮变成圆角,并且通过判断账号密码是否为空来改变按钮颜色。点击按钮时会先本地验证,如果验证失败会弹框,否则进入后台判断。
接下来说下验证码登录跟忘记密码功能
验证码登录,忘记密码,包括账号注册功能都十分相似,基本是通过获取手机或者邮箱,然后向后台接口发送申请,然后通过验证码来判断是否为本人操作,从而进行登录、修改密码、注册账号这三个功能。
发送验证码这个界面的设计跟密码登录差不多,主要需要注意的还是接收验证码后输入的这个模块,因为大多数app的验证码输入界面都不会是简单的一个文本框来输入,而通过一些好看的样式来引导用户输入,这时候就需要我们开发的将一些组件功能组合在一起达到这种效果了。
比如这个文本框的实现,其实是用了Container、Row、TextField还有image来实现的,这个效果其实我也是参考了一个博主的flutter文章来改写的,地址在这里,大概的实现原理就是用一个隐藏的TextField,而且一进入就会获取焦点,验证码的输入框其实是根据这个TextField获取到的数据一一截取然后显示在对应的框上的,输入最后一个字符会自动提交数据,每个框上闪动的焦点提示其实是用一个闪动的gif来实现,会自动在文本的下一格的文本框闪烁。下面码上部分的实现代码
Widget VerificationBox()
{
return new Container(
height: 60,
child:new Stack(
children:new List<Widget> {
new Row(
mainAxisAlignment:MainAxisAlignment.center,
crossAxisAlignment:CrossAxisAlignment.center,
children: GetInputCell()
),
new Container(
height:60,
width:float.PositiveInfinity,
child:new TextField(
keyboardType:TextInputType.number,
inputFormatters:new List<TextInputFormatter>{ new LengthLimitingTextInputFormatter(cellCount) },
decoration:new InputDecoration(border:InputBorder.none),
cursorWidth:0,
style:new TextStyle(color:Colors.transparent),
controller:controller,
autofocus:true,
onChanged:(str)=>
{
setState(()=>
{
code=str;
if(str.Length==cellCount)
{
Debug.Log("提交检测")
}
});
}
)
)
}
)
);
}
string MidStrEx(string sourse, string startstr, string endstr)
{
string result = string.Empty;
int startindex, endindex;
try
{
startindex = sourse.IndexOf(startstr);
if (startindex == -1)
return result;
string tmpstr = sourse.Substring(startindex + startstr.Length);
endindex = tmpstr.IndexOf(endstr);
if (endindex == -1)
return result;
result = tmpstr.Remove(endindex);
}
catch (Exception ex)
{
Debug.Log("MidStrEx Err:" + ex.Message);
}
return result;
}
List<Widget> GetInputCell()
{
List<Widget> list = new List<Widget>();
for (int i = 0; i < cellCount; i++)
{
list.Add(new Expanded(
flex: 1,
child: new Center(child: new Container(
width: 50,
height: 50,
margin: EdgeInsets.only(left: 5, right: 5),
alignment: Alignment.center,
child: GetFoucus(i),
decoration:new BoxDecoration(border: new Border(bottom: new BorderSide(width:1,color: Colors.grey)))
//decoration:new BoxDecoration(border:Border.all(color:Colors.grey,width:1))
)
))
);
}
return list;
}
Widget GetFoucus(int index)
{
if (code.Length == index)
{
return new Container(width: 45, height: 45, child: Image.network(Application.streamingAssetsPath + "/Icons/flash.gif"));
}
else
{
return new Text(
data: GetIndexChar(index),
style: new TextStyle(fontSize: 40, color: Colors.black, fontWeight: FontWeight.w900)
);
}
}
string GetIndexChar(int index)
{
if (code == null || string.IsNullOrEmpty(code))
{
return "";
}
if (code.Length > index)
{
return code[index].ToString();
}
else
{
return "";
}
}
}
忘记密码跟账号注册跟短信登录差不多,这里就不一一说明了。