我们说过Github有多种登录方式,为了简单起见,我们只实现通过用户名和密码登录。在实现登录页时有四点需要注意:
- 可以自动填充上次登录的用户名(如果有)
- 为了防止密码输入错误,密码框应该有开关可以看明文
- 用户名或密码字段在调用登录接口前有本地合法性校验(比如不能为空)
- 登录成功后需更新用户信息
创建lib/routes/LoginRoute.dart文件,实现代码如下:
class LoginRoute extends StatefulWidget {@override_LoginRouteState createState() => _LoginRouteState();}class _LoginRouteState extends State<LoginRoute> {TextEditingController _unameController = new TextEditingController();TextEditingController _pwdController = new TextEditingController();bool pwdShow = false; //密码是否显示明文GlobalKey _formKey = new GlobalKey<FormState>();bool _nameAutoFocus = true;@overridevoid initState() {// 自动填充上次登录的用户名,填充后将焦点定位到密码输入框_unameController.text = Global.profile.lastLogin;if (_unameController.text != null) {_nameAutoFocus = false;}super.initState();}@overrideWidget build(BuildContext context) {var gm = GmLocalizations.of(context);return Scaffold(appBar: AppBar(title: Text(gm.login)),body: Padding(padding: const EdgeInsets.all(16.0),child: Form(key: _formKey,autovalidate: true,child: Column(children: <Widget>[TextFormField(autofocus: _nameAutoFocus,controller: _unameController,decoration: InputDecoration(labelText: gm.userName,hintText: gm.userNameOrEmail,prefixIcon: Icon(Icons.person),),// 校验用户名(不能为空)validator: (v) {return v.trim().isNotEmpty ? null : gm.userNameRequired;}),TextFormField(controller: _pwdController,autofocus: !_nameAutoFocus,decoration: InputDecoration(labelText: gm.password,hintText: gm.password,prefixIcon: Icon(Icons.lock),suffixIcon: IconButton(icon: Icon(pwdShow ? Icons.visibility_off : Icons.visibility),onPressed: () {setState(() {pwdShow = !pwdShow;});},)),obscureText: !pwdShow,//校验密码(不能为空)validator: (v) {return v.trim().isNotEmpty ? null : gm.passwordRequired;},),Padding(padding: const EdgeInsets.only(top: 25),child: ConstrainedBox(constraints: BoxConstraints.expand(height: 55.0),child: RaisedButton(color: Theme.of(context).primaryColor,onPressed: _onLogin,textColor: Colors.white,child: Text(gm.login),),),),],),),),);}void _onLogin() async {// 提交前,先验证各个表单字段是否合法if ((_formKey.currentState as FormState).validate()) {showLoading(context);User user;try {user = await Git(context).login(_unameController.text, _pwdController.text);// 因为登录页返回后,首页会build,所以我们传false,更新user后不触发更新Provider.of<UserModel>(context, listen: false).user = user;} catch (e) {//登录失败则提示if (e.response?.statusCode == 401) {showToast(GmLocalizations.of(context).userNameOrPasswordWrong);} else {showToast(e.toString());}} finally {// 隐藏loading框Navigator.of(context).pop();}if (user != null) {// 返回Navigator.of(context).pop();}}}}
代码很简单,关键地方都有注释,不再赘述,下面我们看一下运行效果,如图所示。
