如果路上有坑,就要毫不犹豫的跳下去
登陆页是一个软件的门面。一个完整的登陆页包含账号密码登陆、验证码登陆、注册及忘记密码四个功能,下面从框架开始一步步完成。
踩坑记录:
- 背景图由于键盘弹起导致图片变形
- 输入框由于键盘弹起上移,虽然避免了键盘遮挡,但是效果不好
如果你只想看代码,请到页面最下方,有完整代码
搭建环境
1. 封装网络请求库
登陆功能需要实现网络请求的功能,引入dio库来进行网络请求类的封装,需要学习的可以参考pub官网的教程,有中文版哦
dio是一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时、自定义适配器等…
为了方便使用,Dio提供了一些其它的Restful API, 这些API都是request
的别名。
2. 导入持久存储库
shared_preferences
为简单数据提供一个持久的存储。数据被异步地持久化到磁盘。需要注意的一点是,两个平台都不能保证写操作在返回后被持久化到磁盘上,所以这个插件不能用于存储关键数据。
这里主要用于缓存一下token
编写widget
如何搭建程序框架就不在这里介绍了,下面主要讲解登陆页面的搭建
给页面加个背景图
class LoginPage extends StatefulWidget {
static final String sName = "login";
@override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return new Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('static/images/login_back.jpeg'),
fit: BoxFit.cover,
),
),
);
}
}
最外围的Container在默认情况下会铺满整个屏幕,使用BoxDecoration对container进行装饰。
这里有个坑需要注意一下,一般情况下我们都会用Scaffold
来包装整个页面,因为这个组件提供了一系列非常方便的属性来配置整个页面,但如果我们想要一个背景图,就必须先写一个Container,因为如果使用Scaffold
,就会在键盘弹出的时候导致页面重绘,背景图会受到挤压而变形。
编写页面主体
这时候就可以使用Scaffold
模块来写页面了。
@override
Widget build(BuildContext context) {
return new Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('static/images/login_back.jpeg'),
fit: BoxFit.cover,
),
),
child: Scaffold(
resizeToAvoidBottomPadding: false, // 这里需要注意一下
backgroundColor: Color.fromARGB(150, 255, 255, 255),
body: Container(
padding: EdgeInsets.all(40),
child: getLoginComp(),
),
),
);
}
这里也有一个坑,Scaffold
在键盘弹出的时候,会由于底部的挤压而重绘页面,我们已经避免了背景图的变形,但是 Scaffold
模块内部的组件会在键盘弹出的时候整体向上偏移,这个特性可以解决输入框被键盘遮挡的问题,但是有些人可能不需要这一特性,可以将resizeToAvoidBottomPadding
属性设置为false。
编写用户名及密码输入框
// 用户名输入框
TextField(
controller: _usernameController,
decoration: InputDecoration(
// labelText: "用户名",
hintText: "手机号",
prefixIcon: Icon(Icons.person), // 前置
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: // 椭圆形输入外框
OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
),
keyboardType: TextInputType.number, // 弹起的键盘类型
inputFormatters: [ // 输入校验,这里只允许输入数字
WhitelistingTextInputFormatter(RegExp("[0-9]")),
]),
/// 密码输入框
TextField(
controller: _passwordController,
decoration: InputDecoration(
// labelText: "密码",
hintText: "您的登录密码",
prefixIcon: Icon(Icons.lock),
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
),
obscureText: true,
);
验证码输入框
因为我想把验证码按钮放到输入框里,所以使用stack组件进行包裹
Stack(
children: <Widget>[
TextField(
// autofocus: true,
keyboardType: TextInputType.number,
controller: _verCodeController,
decoration: InputDecoration(
prefixIcon: Icon(Icons.