第四章、用flutter创建登录界面

让我们回想下android做一个登录界面需要什么。一个登录界面顶部logo、logo下一个登录标题、一个用户名输入框、一个密码输入框、一个登录按钮。如下图:

一、我们新创建一个登录的页面,flutter的界面创建和andorid的有所不同,android的是一个activity+layout.xml,而flutter的是一个Page+一个PageState :

Page:

复制代码
class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

一般都继承StatefulWidget。

PageState:

复制代码
class _LoginPageState extends State<LoginPage> {
复制代码
@override
Widget build(BuildContext context) {

........ 这里是创建界面的代码

}

}

PageState里面必须有build方法,还可以继承其它法如:

1、@override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); //添加观察者 }

2、// 生命周期变化时回调 // resumed:应用可见并可响应用户操作,app进入前台 // inactive:用户可见,但不可响应用户操作,比如来了个电话,前后台切换的过渡状态 // paused:已经暂停了,用户不可见、不可操作,app进入后台 // suspending:应用被挂起,此状态IOS永远不会回调 @override void didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); print("didChangeAppLifecycleState: $state"); }

3、//当前系统改变了一些访问性活动的回调 @override void didChangeAccessibilityFeatures() { super.didChangeAccessibilityFeatures(); print("didChangeAccessibilityFeatures"); }

4、//低内存回调 @override void didHaveMemoryPressure() { super.didHaveMemoryPressure(); print("didHaveMemoryPressure"); }

5、//应用尺寸改变时回调,例如旋转 @override void didChangeMetrics() { super.didChangeMetrics(); Size size = WidgetsBinding.instance.window.physicalSize; print("didChangeMetrics :宽:{size.width} 高:{size.height}"); }

6、@override void dispose() { super.dispose(); WidgetsBinding.instance.removeObserver(this); //销毁观察者 }

二、当我们的登录界面的主类建好后,下面我们要做的是怎么绘制一个完整的登录界面:

如果有学习过js框架里面的extjs,会对flutter创建界面的方式有很熟悉的感觉。

这里我们用:

复制代码
Container + SingleChildScrollView 做整体布局,Container做整个的组合容器,同时加渐变颜色,当然也可以加背景图,SingleChildScrollView  里面加Column的子控件,column下加多个字控件,子控件居中。完整的创建界面代码如下:
复制代码
Scaffold(
  body: Container(
    decoration: BoxDecoration(
      gradient: LinearGradient(// 使用线性渐变
        begin: Alignment.topLeft,// 渐变开始位置
        end: Alignment.bottomRight, // 渐变结束位置
        colors: [ // 定义渐变颜色列表
          Colors.blueAccent,// 起始颜色
          Colors.purpleAccent// 结束颜色
        ],
      ),
    ),
    child: Center(
      child: SingleChildScrollView(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(//用于垂直堆叠子控件
            mainAxisAlignment: MainAxisAlignment.center,//所有子控件居中
            children: <Widget>[
            Image.asset(
               "assets/images/go_logo.png",
                width: 100,
                height: 100,
              ),
              SizedBox(height: 20.0),//加一个空白行
              // 提示文本
              Text(
                '欢迎回来',
                style: TextStyle(
                  fontSize: 24.0,
                  fontWeight: FontWeight.bold,
                  color: Colors.white,
                ),
              ),
              SizedBox(height: 20.0),
              // 账号输入框
              TextField(
                controller: _usernameController,
                decoration: InputDecoration(
                  filled: true,
                  fillColor: Colors.white,
                  hintText: '账号',
                  prefixIcon: Icon(Icons.person),
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(10.0),
                    borderSide: BorderSide.none,
                  ),
                ),
              ),
              SizedBox(height: 10.0),
              // 密码输入框
              TextField(
                controller: _passwordController,
                obscureText: true,
                decoration: InputDecoration(
                  filled: true,
                  fillColor: Colors.white,
                  hintText: '密码',
                  prefixIcon: Icon(Icons.lock),
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(10.0),
                    borderSide: BorderSide.none,
                  ),
                ),
              ),
              SizedBox(height: 20.0),
              // 登录按钮
              ElevatedButton(
                onPressed: _login,
                style: ElevatedButton.styleFrom(
                  foregroundColor: Colors.blueAccent,
                  backgroundColor: Colors.white,
                  padding: EdgeInsets.symmetric(
                    horizontal: 50,
                    vertical: 15,
                  ),
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(10.0),
                  ),
                ),
                child: Text(
                  '立即登录',
                  style: TextStyle(
                    fontSize: 18.0,
                    fontWeight: FontWeight.bold,
                  ),
                ),
              ),
              SizedBox(height: 10.0),
              // 忘记密码按钮
              TextButton(
                onPressed: () {
                  Navigator.of(context).push(MyRoute(FindPasswordPage()));
                  // Navigator.push(context, MaterialPageRoute(builder: (context) {
                  //   return FindPasswordPage();
                  // }));
                },
                child: Text(
                  '忘记密码?',
                  style: TextStyle(color: Colors.white, fontSize: 16.0),
                ),
              ),
              SizedBox(height: 20.0),
              // 注册提示
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(
                    '还没有账号? ',
                    style: TextStyle(color: Colors.white, fontSize: 16.0),
                  ),
                  TextButton(
                    onPressed: () {
                      _register();
                    },
                    child: Text(
                      '立即注册',
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 16.0,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    ),
  ),
);

三、very good 现在我们已经创建好了登录界面,那么已经完成工作了吗,当然不是,整个界面还不能点击,无法响应登录事件:

我们需要做三件事:获取点击事件、获取用户名、获取密码。

1、获取点击事件:

ElevatedButton( onPressed: _login 从上面代码可以看到ElevatedButton 有一个onPressed接收点击事件方法,点击后直接调用_login调用登录方法:

复制代码
// 登录逻辑
void _login() {
  _usernameController.text = "lb";
  _passwordController.text = "123";
  String username = _usernameController.text.trim();
  String password = _passwordController.text.trim();
  Result loginResult = loginService.login(username, password);
  // 验证账号和密码是否为空
  if (loginResult.result == false) {
    String? errorMessage = loginResult.resultMessage;
    Fluttertoast.showToast(
        msg: errorMessage??"",
        toastLength: Toast.LENGTH_LONG,
        gravity: ToastGravity.CENTER,
        timeInSecForIosWeb: 1,
        backgroundColor: Colors.black,
        textColor: Colors.white,
        fontSize: 16.0
    );
  }else {
    _goToMainPage();
  }
}

2、获取用户名和密码

这里我们还注意到要获取登录名和密码,需要有两个和text绑定的controller:

复制代码
// 用于保存用户输入的账号和密码
final TextEditingController _usernameController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();

这一点和我们写android和ios有所区别的哦。

TextEditingController是一个核心类,用于控制文本输入框(如TextField或TextFormField)的文本内容、焦点和事件监听。它允许开发者动态设置初始文本、获取用户输入、监听变化并管理资源。

四、下面我把整个代码片段奉上:

复制代码
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:aieshop/findpassword.dart';
import 'package:aieshop/route.dart';
import 'package:aieshop/register.dart';
import 'package:aieshop/homepage.dart';
import 'package:aieshop/service/login/LoginService.dart';
import 'package:aieshop/service/base/baseservice.dart';
class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  LoginService loginService = LoginService();
  // 用于保存用户输入的账号和密码
  final TextEditingController _usernameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  // 登录逻辑
  void _login() {
    _usernameController.text = "lb";
    _passwordController.text = "123";
    String username = _usernameController.text.trim();
    String password = _passwordController.text.trim();
    Result loginResult = loginService.login(username, password);
    // 验证账号和密码是否为空
    if (loginResult.result == false) {
      String? errorMessage = loginResult.resultMessage;
      Fluttertoast.showToast(
          msg: errorMessage??"",
          toastLength: Toast.LENGTH_LONG,
          gravity: ToastGravity.CENTER,
          timeInSecForIosWeb: 1,
          backgroundColor: Colors.black,
          textColor: Colors.white,
          fontSize: 16.0
      );
    }else {
      _goToMainPage();
    }
  }

  void _register(){
    Navigator.of(context).push(MyRoute(RegisterPage()));
  }

  void _goToMainPage(){
    Navigator.of(context).push(MyRoute(WillPopScopeHome()));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        decoration: BoxDecoration(
          gradient: LinearGradient(// 使用线性渐变
            begin: Alignment.topLeft,// 渐变开始位置
            end: Alignment.bottomRight, // 渐变结束位置
            colors: [ // 定义渐变颜色列表
              Colors.blueAccent,// 起始颜色
              Colors.purpleAccent// 结束颜色
            ],
          ),
        ),
        child: Center(
          child: SingleChildScrollView(
            child: Padding(
              padding: const EdgeInsets.all(16.0),
              child: Column(//用于垂直堆叠子控件
                mainAxisAlignment: MainAxisAlignment.center,//所有子控件居中
                children: <Widget>[
                Image.asset(
                   "assets/images/go_logo.png",
                    width: 100,
                    height: 100,
                  ),
                  SizedBox(height: 20.0),//加一个空白行
                  // 提示文本
                  Text(
                    '欢迎回来',
                    style: TextStyle(
                      fontSize: 24.0,
                      fontWeight: FontWeight.bold,
                      color: Colors.white,
                    ),
                  ),
                  SizedBox(height: 20.0),
                  // 账号输入框
                  TextField(
                    controller: _usernameController,
                    decoration: InputDecoration(
                      filled: true,
                      fillColor: Colors.white,
                      hintText: '账号',
                      prefixIcon: Icon(Icons.person),
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(10.0),
                        borderSide: BorderSide.none,
                      ),
                    ),
                  ),
                  SizedBox(height: 10.0),
                  // 密码输入框
                  TextField(
                    controller: _passwordController,
                    obscureText: true,
                    decoration: InputDecoration(
                      filled: true,
                      fillColor: Colors.white,
                      hintText: '密码',
                      prefixIcon: Icon(Icons.lock),
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(10.0),
                        borderSide: BorderSide.none,
                      ),
                    ),
                  ),
                  SizedBox(height: 20.0),
                  // 登录按钮
                  ElevatedButton(
                    onPressed: _login,
                    style: ElevatedButton.styleFrom(
                      foregroundColor: Colors.blueAccent,
                      backgroundColor: Colors.white,
                      padding: EdgeInsets.symmetric(
                        horizontal: 50,
                        vertical: 15,
                      ),
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(10.0),
                      ),
                    ),
                    child: Text(
                      '立即登录',
                      style: TextStyle(
                        fontSize: 18.0,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                  SizedBox(height: 10.0),
                  // 忘记密码按钮
                  TextButton(
                    onPressed: () {
                      Navigator.of(context).push(MyRoute(FindPasswordPage()));
                      // Navigator.push(context, MaterialPageRoute(builder: (context) {
                      //   return FindPasswordPage();
                      // }));
                    },
                    child: Text(
                      '忘记密码?',
                      style: TextStyle(color: Colors.white, fontSize: 16.0),
                    ),
                  ),
                  SizedBox(height: 20.0),
                  // 注册提示
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(
                        '还没有账号? ',
                        style: TextStyle(color: Colors.white, fontSize: 16.0),
                      ),
                      TextButton(
                        onPressed: () {
                          _register();
                        },
                        child: Text(
                          '立即注册',
                          style: TextStyle(
                            color: Colors.white,
                            fontSize: 16.0,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}
相关推荐
搬砖的kk2 小时前
基于Flutter开发应用如何快速适配HarmonyOS
flutter·华为·harmonyos
昼-枕3 小时前
Flutter深度解析:如何构建高性能、跨平台的移动应用
flutter
音浪豆豆_Rachel4 小时前
Flutter 与原生通信的桥梁:深入解析 Pigeon 与后台线程通信
flutter·harmonyos
音浪豆豆_Rachel5 小时前
Flutter跨平台通信的智能配置:Pigeon注解配置与鸿蒙生态深度集成
flutter·华为·harmonyos
Bryce李小白5 小时前
深入理解WidgetsFlutterBinding
flutter
开心_开心急了5 小时前
Ai加Flutter实现自定义标题栏(appBar)
前端·flutter
全栈派森6 小时前
Flutter 实战:基于 GetX + Obx 的企业级架构设计指南
前端·flutter
yuezhilangniao11 小时前
Windows版Flutter环境部署速查指南- win10开发环境flutter
windows·flutter