Flutter實戰(zhàn) 登錄頁

2021-03-09 15:14 更新

我們說過 Github 有多種登錄方式,為了簡單起見,我們只實現(xiàn)通過用戶名和密碼登錄。在實現(xiàn)登錄頁時有四點需要注意:

  1. 可以自動填充上次登錄的用戶名(如果有)。
  2. 為了防止密碼輸入錯誤,密碼框應(yīng)該有開關(guān)可以看明文。
  3. 用戶名或密碼字段在調(diào)用登錄接口前有本地合法性校驗(比如不能為空)。
  4. 登錄成功后需更新用戶信息。

實現(xiàn)代碼如下:

  1. import '../index.dart';
  2. class LoginRoute extends StatefulWidget {
  3. @override
  4. _LoginRouteState createState() => _LoginRouteState();
  5. }
  6. class _LoginRouteState extends State<LoginRoute> {
  7. TextEditingController _unameController = new TextEditingController();
  8. TextEditingController _pwdController = new TextEditingController();
  9. bool pwdShow = false; //密碼是否顯示明文
  10. GlobalKey _formKey = new GlobalKey<FormState>();
  11. bool _nameAutoFocus = true;
  12. @override
  13. void initState() {
  14. // 自動填充上次登錄的用戶名,填充后將焦點定位到密碼輸入框
  15. _unameController.text = Global.profile.lastLogin;
  16. if (_unameController.text != null) {
  17. _nameAutoFocus = false;
  18. }
  19. super.initState();
  20. }
  21. @override
  22. Widget build(BuildContext context) {
  23. var gm = GmLocalizations.of(context);
  24. return Scaffold(
  25. appBar: AppBar(title: Text(gm.login)),
  26. body: Padding(
  27. padding: const EdgeInsets.all(16.0),
  28. child: Form(
  29. key: _formKey,
  30. autovalidate: true,
  31. child: Column(
  32. children: <Widget>[
  33. TextFormField(
  34. autofocus: _nameAutoFocus,
  35. controller: _unameController,
  36. decoration: InputDecoration(
  37. labelText: gm.userName,
  38. hintText: gm.userNameOrEmail,
  39. prefixIcon: Icon(Icons.person),
  40. ),
  41. // 校驗用戶名(不能為空)
  42. validator: (v) {
  43. return v.trim().isNotEmpty ? null : gm.userNameRequired;
  44. }),
  45. TextFormField(
  46. controller: _pwdController,
  47. autofocus: !_nameAutoFocus,
  48. decoration: InputDecoration(
  49. labelText: gm.password,
  50. hintText: gm.password,
  51. prefixIcon: Icon(Icons.lock),
  52. suffixIcon: IconButton(
  53. icon: Icon(
  54. pwdShow ? Icons.visibility_off : Icons.visibility),
  55. onPressed: () {
  56. setState(() {
  57. pwdShow = !pwdShow;
  58. });
  59. },
  60. )),
  61. obscureText: !pwdShow,
  62. //校驗密碼(不能為空)
  63. validator: (v) {
  64. return v.trim().isNotEmpty ? null : gm.passwordRequired;
  65. },
  66. ),
  67. Padding(
  68. padding: const EdgeInsets.only(top: 25),
  69. child: ConstrainedBox(
  70. constraints: BoxConstraints.expand(height: 55.0),
  71. child: RaisedButton(
  72. color: Theme.of(context).primaryColor,
  73. onPressed: _onLogin,
  74. textColor: Colors.white,
  75. child: Text(gm.login),
  76. ),
  77. ),
  78. ),
  79. ],
  80. ),
  81. ),
  82. ),
  83. );
  84. }
  85. void _onLogin() async {
  86. // 提交前,先驗證各個表單字段是否合法
  87. if ((_formKey.currentState as FormState).validate()) {
  88. showLoading(context);
  89. User user;
  90. try {
  91. user = await Git(context).login(_unameController.text, _pwdController.text);
  92. // 因為登錄頁返回后,首頁會build,所以我們傳false,更新user后不觸發(fā)更新
  93. Provider.of<UserModel>(context, listen: false).user = user;
  94. } catch (e) {
  95. //登錄失敗則提示
  96. if (e.response?.statusCode == 401) {
  97. showToast(GmLocalizations.of(context).userNameOrPasswordWrong);
  98. } else {
  99. showToast(e.toString());
  100. }
  101. } finally {
  102. // 隱藏loading框
  103. Navigator.of(context).pop();
  104. }
  105. if (user != null) {
  106. // 返回
  107. Navigator.of(context).pop();
  108. }
  109. }
  110. }
  111. }

代碼很簡單,關(guān)鍵地方都有注釋,不再贅述,下面我們看一下運行效果,如圖15-5所示。

圖15-5

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號