0. 项目简介

项目想法脱胎于2023年服务外包大赛A18题 随手买(详情

整个APP思路如下:

在这里插入图片描述

这篇博客主要服务于登录界面,逻辑思路如下:

在这里插入图片描述

主要用的就是数据库的知识和界面设计的知识。

1. 效果展示

界面

在这里插入图片描述

点击指纹识别按钮查看作者信息

在这里插入图片描述

创建数据库

请添加图片描述

注册账号

请添加图片描述

修改密码

在这里插入图片描述

根据不同身份登录到不同界面(每个身份的子界面代码不在本章博客中)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2. 代码

依赖如下

dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_screenutil: ^3.1.0
  sqflite: ^1.1.0
  path_provider: ^2.0.5
  font_awesome_flutter: 8.2.0

相关文件如下

main.dart
LoginPage.dart

main.dart

import 'package:flutter/material.dart';
import 'LoginPage.dart';
// 这几个包其实都不用管,是注册路由的时候用的
import 'passenger.dart';
import 'drivermoney.dart';
import 'adminpage.dart';
// import 'try.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      // home: Scaffold(
      //   body: TabsNonScrollableDemo(),
      // ),
      routes:{                     //注册路由
        'login':(context)=>LoginPage(),
        'userhome':(context)=>passenger(),
        'driverhome':(context)=>drivermoney(),
        'adminhome':(context)=>adminpage(),
      },
      initialRoute: 'login',
    );
  }
}

LoginPage.dart

import 'package:flutter/material.dart';
import 'myself.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';


var showContent = ""; //身份
var password = '';//密码
var username = '';//用户名

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      // home: Scaffold(
      //   body: TabsNonScrollableDemo(),
      // ),
      routes:{                     //注册路由
        'login':(context)=>LoginPage(),
      },
      initialRoute: 'login',
    );
  }
}

class LoginPage extends StatefulWidget {
  const LoginPage({Key? key}) : super(key: key);

  
  State<LoginPage> createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  // 几个变量
  var _isShowPwd = false;//是否显示密码
  var _isShowClear = false;//是否显示输入框尾部的清除按钮
  bool _trusthim = false;

  var _strNewUsername = '';
  var _strNewPwd = '';
  var _newshowContent = '';

  var _forgetNewUsername = '';
  var _forgetNewPwd = '';
  var _forgetshowContent = '';

  var _user_count = 1;
  bool _test_have = false;


  // 下拉框输入内容
  List<String> dropList = <String>['      请选择您的身份', '      用户', '      司机', '      管理员'];


  String myDataBase = "usermessage.db";

  //数据库路径
  String myDataBasePath = "";

  //数据库中的表 简单一点,就创建三个字段,分别是主键,用户名,密码
  String sql_createUserTable = "CREATE TABLE user("
      "id INTEGER PRIMARY KEY,"
      "kind TEXT,"
      "username TEXT,"
      "password TEXT)";

  //查找数据库表的数目
  String sql_queryCount = 'SELECT COUNT(*) FROM user';

  //具体查找数据库表的所有信息
  String sql_queryMessage = 'SELECT * FROM user';

  //这是从数据库表返回数据
  var _data;

  //创建数据库
  Future<String> createDataBase(String db_name) async {
    //在文档目录建立
    var document = await getApplicationDocumentsDirectory();
    //获取路径 join是path包下的方法,就是将两者路径连接起来
    String path = join(document.path, db_name);
    //逻辑是如果数据库存在就把它删除然后创建
    var _directory = new Directory(dirname(path));
    bool exists = await _directory.exists();
    if (exists) {
      //必存在 这里是为了每次创建数据库表先表删除则删除数据库表
      await deleteDatabase(path);
    } else {
      try {
        //不存在则创建目录  如果[recursive]为false,则只有路径中的最后一个目录是
        //创建。如果[recursive]为真,则所有不存在的路径
        //被创建。如果目录已经存在,则不执行任何操作。
        await new Directory(dirname(path)).create(recursive: true);
      } catch (e) {
        print(e);
      }
    }
    return path;
  }

  //创建数据库表方法
  cratedb_table() async {
    //得到数据库的路径
    myDataBasePath = await createDataBase(myDataBase);
    //打开数据库
    Database my_db = await openDatabase(myDataBasePath);
    //创建数据库表
    await my_db.execute(sql_createUserTable);
    //关闭数据库
    await my_db.close();
    setState(() {
      _data = "创建usermessage.db成功,创建user表成功~";
    });
  }

  //增加方法
  addData() async {
    print("$_newshowContent");
    //首先打开数据库
    Database my_db = await openDatabase(myDataBasePath);
    //插入数据
    String add_sql = "INSERT INTO user(kind,username,password) VALUES('$_newshowContent','$_strNewUsername','$_strNewPwd')";
    await my_db.transaction((tran) async{
      await tran.rawInsert(add_sql);
    });
    //关闭数据库
    await my_db.close();
    setState(() {
      query_num();
      _data = "增加一条数据成功,类别是:$_newshowContent,名字是:$_strNewUsername,密码是:$_strNewUsername";
    });

  }

  //查询具体数值
  queryDetail() async{
    //打开数据库
    Database  my_db = await openDatabase(myDataBasePath);
    //将数据放到集合里面显示
    List<Map> dataList = await my_db.rawQuery(sql_queryMessage);
    await my_db.close();
    setState(() {
      _data = "具体数据详情如下:$dataList";
    });
  }

  //删除一条数据
  delete() async {
    Database my_db = await openDatabase(myDataBasePath);
    //根据id来删除 也可以根据其他信息来删除 例如名字
    String delete_ssql = "DELETE FROM user WHERE id = ?";
    //返回所更改的数目
    int delete_count = await my_db.rawDelete(delete_ssql,['1']);
    //关闭数据库
    await my_db.close();
    //状态更新
    setState(() {
      if(delete_count == 1){
        _data = "删除成功~";
      } else {
        _data = "删除失败,请看错误日志~";
      }
    });
  }

  //修改数据方法
  update() async{
    //数据库
    Database my_db = await openDatabase(myDataBasePath);
    // String update_sql = "UPDATE user SET password = ? WHERE username = ? AND kind = ?";
    // await my_db.rawUpdate(update_sql,['$_forgetNewPwd','$_forgetNewUsername', '$_forgetshowContent']);
    await my_db.update(
      "user",
      {'password': '$_forgetNewPwd'},
      where: 'username = ? AND kind = ?', // 查询条件
      whereArgs: ['$_forgetNewUsername', "$_forgetshowContent"],
    );
    // queryDetail();
    await my_db.close();

    setState(() {
      _data = "数据修改成功,请查阅~";
    });

  }

  //查询有几条
  query_num() async{
    //数据库
    Database my_db = await openDatabase(myDataBasePath);
    //用sqflite包的方法firstInValue
    int data_count = Sqflite.firstIntValue(await my_db.rawQuery(sql_queryCount));
    await my_db.close();
    setState(() {
      _data = "数据条数:$data_count";
      _user_count = data_count+1;
    });
  }

  //查询修改密码数据是否存在
  querysampleDetail() async{
    //打开数据库
    Database my_db = await openDatabase(myDataBasePath);
    List<Map<String, dynamic>> result = await my_db.query(
      "user",
      distinct: true, // 是否是独特的,即是否不让重复
      columns: ['id'], // 需要查询的列
      where: 'username = ? AND kind = ?', // 查询条件
      whereArgs: ['$_forgetNewUsername', "$_forgetshowContent"],
    );
    print("修改:$result");
    // print(result);
    // List<Map> dataList = await my_db.rawQuery("SELECT * FROM user WHERE username = '$_forgetNewUsername'");
    // print(dataList);
    // String fun = "SELECT COUNT(*) FROM user WHERE username = '$_forgetNewUsername' AND kind = '$_forgetshowContent'";
    //将数据放到集合里面显示
    // List<Map> dataList = await my_db.rawQuery('SELECT * FROM user WHERE username = $_newusername AND kind = $_newshowContent');
    // int data_count = Sqflite.firstIntValue(await my_db.rawQuery(fun));
    int data_count = result.length;
    await my_db.close();
    setState(() {
      if (data_count != 0){
        _trusthim = true;
      } else{
        _trusthim = false;
      }
    });
  }

  //查询是否存在该用户、密码
  queryuserDetail() async{
    //打开数据库
    Database my_db = await openDatabase(myDataBasePath);
    List<Map<String, dynamic>> result = await my_db.query(
      "user",
      distinct: true, // 是否是独特的,即是否不让重复
      columns: ['id'], // 需要查询的列
      where: 'username = ? AND kind = ? AND password = ?', // 查询条件
      whereArgs: ['$username', "$showContent", '$password'],
    );
    print("登录:$result");
    int data_count = result.length;
    await my_db.close();
    setState(() {
      if (data_count != 0){
        _test_have = true;
      } else {
        _test_have = false;
      }
    });
  }


  // 注册用户名
  TextEditingController _newusername = TextEditingController();
  TextEditingController _newpwd = TextEditingController();

  TextEditingController _newusername2 = TextEditingController();
  TextEditingController _newpwd2 = TextEditingController();


  
  void initState() {
    super.initState();
    showContent = dropList.first;
  }

  
  Widget build(BuildContext context) {
    // 初始化屏幕
    ScreenUtil.init(context, allowFontScaling: false);

    //表单
    GlobalKey<FormState> _formKey = GlobalKey<FormState>();


    //用户名输入框控制器,此控制器可以监听用户名输入框操作
    TextEditingController _userNameController = TextEditingController();

    // logo
    Widget logoImageArea = Container(
      alignment: Alignment.topCenter,
      height: 200,
      width: 200,
      decoration: const BoxDecoration(
        image: DecorationImage(image: AssetImage('assets/images/LOGO_w.png')),
        color: Colors.transparent,
        borderRadius: BorderRadius.only(
            topLeft: Radius.circular(5), topRight: Radius.circular(5)),
      ),
    );


    // 输入框
    Widget inputTextArea = Container(
      margin: EdgeInsets.only(left: 20,right: 20),
      decoration: BoxDecoration(
          borderRadius: BorderRadius.all(Radius.circular(8)),
          color: Colors.white
      ),
      // 这边放一个表单用于校验
      // child: Form(
      //   key: _formKey,
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          DropdownButtonFormField(
            // 显示选择结果
            value: showContent,
            // 生成结果
            items: dropList.map<DropdownMenuItem<String>>((String value) {
              return DropdownMenuItem<String>(
                value: value,
                child: Text(value, textAlign: TextAlign.center),
              );
            }).toList(),
            // 按钮菜单选择回调
            onChanged: (String? value) {
              setState(() {
                showContent = value!;
              });
            },
            // hint: Text(_showContent,style: TextStyle(color: Colors.black),),
            isDense: true,
            style: TextStyle(color: Colors.grey.shade600,),
            iconEnabledColor:Colors.grey.shade600,
            iconDisabledColor: Colors.grey.shade600,
          ),


          // 用户名
          TextFormField(
            decoration: InputDecoration(
              labelText: "用户名",
              hintText: "请输入手机号或创建账号",
              prefixIcon: Icon(Icons.person),
              // 尾部添加清除按钮
              suffixIcon: username.isEmpty ? null : IconButton(
                icon: Icon(Icons.clear),
                onPressed: (){
                  _userNameController.clear();
                },
              ) ,
            ),
            onChanged: (user) {
              //获取用户名
              username = user;
            },
          ),

          // 密码
          TextFormField(
            decoration: InputDecoration(
                labelText: "密码",
                hintText: "请输入密码",
                prefixIcon: Icon(Icons.lock),
                // 尾部添加显示密码
                suffixIcon: IconButton(
                  icon: Icon(_isShowPwd ? Icons.visibility : Icons.visibility_off),
                  // 点击了切换密码状态
                  onPressed: (){
                    setState(() {
                      _isShowPwd = !_isShowPwd;
                    });
                  },
                )
            ),
            obscureText: !_isShowPwd,
            onChanged: (pwd) {
              //获取用户密码
              password = pwd;
            },
          )
        ],
      ),
    );


    // 登录按钮
    Widget loginButtonArea = Container(
      margin: EdgeInsets.only(left: 20,right: 20),
      height: 45.0,
      child: MaterialButton(
        color: Colors.blue[300],
        child: Text(
          "登录",
          style: Theme.of(context).primaryTextTheme.headline5,
        ),
        // 设置按钮圆角
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
        onPressed: (){
          if(username!="" && password!="" && showContent!="" && showContent!=dropList[0]){
            queryuserDetail();
            if (_test_have==true){
              if(showContent==dropList[1]){
                Navigator.pushNamed(context,"userhome");
              }else if(showContent==dropList[2]){
                Navigator.pushNamed(context,"driverhome");
              }else if(showContent==dropList[3]){
                Navigator.pushNamed(context,"adminhome");
              }else{
                Fluttertoast.showToast(
                  msg: "请选择身份",
                  toastLength: Toast.LENGTH_SHORT,
                  gravity: ToastGravity.BOTTOM,
                );
              }
            }
            else{
              Fluttertoast.showToast(
                msg: "用户名密码不正确",
                toastLength: Toast.LENGTH_SHORT,
                gravity: ToastGravity.BOTTOM,
                // timeInSecForIos:1
              );
            }
          }else {
            Fluttertoast.showToast(
              msg: "输入不能为空!!",
              toastLength: Toast.LENGTH_SHORT,
              gravity: ToastGravity.BOTTOM,
              // timeInSecForIos:1
            );
          }
        },
      ),
    );



    // 三个Icon看看
    Widget thirdLoginArea = Container(
      margin: EdgeInsets.only(left: 20,right: 20),
      child: Column(
        children: <Widget>[
          Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: <Widget>[
              Container(
                width: 80,
                height: 1.0,
                color: Colors.grey,
              ),
              Text(
                  '第三方登录'
              ),
              Container(
                width: 80,
                height: 1.0,
                color: Colors.grey,
              ),
            ],
          ),
          SizedBox(
            height: 18,
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: <Widget>[
              IconButton(
                color: Colors.green[200],
                // 第三方库icon图标
                icon: Icon(FontAwesomeIcons.weixin),
                iconSize: 40.0,
                onPressed: (){ },
              ),
              IconButton(
                color: Colors.green[200],
                icon: Icon(FontAwesomeIcons.facebook),
                iconSize: 40.0,
                onPressed: (){ },
              ),
              IconButton(
                color: Colors.green[200],
                icon: Icon(FontAwesomeIcons.qq),
                iconSize: 40.0,
                onPressed: (){ },
              )
            ],
          )
        ],
      ),
    );


    fastregister(BuildContext context) async {
      return showDialog(
          context: context,
          builder: (context) {
            return AlertDialog(
              title: const Text('TextField AlertDemo'),
              content: SizedBox(
                width: 300,
                height: 200,
                child: Column(
                  children: [
                    DropdownButtonFormField(
                      // 显示选择结果
                      value: dropList.first,
                      // 生成结果
                      items: dropList.map<DropdownMenuItem<String>>((String value) {
                        return DropdownMenuItem<String>(
                          value: value,
                          child: Text(value, textAlign: TextAlign.center),
                        );
                      }).toList(),
                      // 按钮菜单选择回调
                      onChanged: (String? value) {
                        setState(() {
                          _newshowContent = value!;
                        });
                      },
                      isDense: true,
                      style: TextStyle(color: Colors.grey.shade600,),
                      iconEnabledColor:Colors.grey.shade600,
                      iconDisabledColor: Colors.grey.shade600,
                    ),
                    TextField(
                      controller: _newusername,
                      decoration: const InputDecoration(hintText: "用户名"),
                      onChanged: (newuser) {
                        //获取用户名
                        _strNewUsername = newuser;
                      },
                    ),
                    TextField(
                      controller: _newpwd,
                      decoration: const InputDecoration(hintText: "密码"),
                      onChanged: (newpwd) {
                        //获取用户名
                        _strNewPwd = newpwd;
                      },
                    ),
                  ],
                ),
              ),

              actions: <Widget>[
                MaterialButton(
                  color: Colors.teal,
                  child: const Text('取消'),
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                ),
                MaterialButton(
                  color: Colors.teal,
                  child: const Text('快速注册'),
                  onPressed: () {
                    if(_strNewUsername!="" && _strNewPwd!="" && _newshowContent!="" && _newshowContent!=dropList[0]){
                      addData();

                      Fluttertoast.showToast(
                        msg: "注册成功,欢饮您称为Clark NB的第${_user_count}位用户。",
                        toastLength: Toast.LENGTH_SHORT,
                        gravity: ToastGravity.BOTTOM,
                      );
                      Navigator.of(context).pop();
                    }else{
                      Fluttertoast.showToast(
                        msg: "信息有误,请重新输入",
                        toastLength: Toast.LENGTH_SHORT,
                        gravity: ToastGravity.BOTTOM,
                      );
                    }
                  },
                ),
              ],
            );
          });
    }

    forget(BuildContext context) async {
      return showDialog(
          context: context,
          builder: (context) {
            return AlertDialog(
              title: const Text('TextField AlertDemo'),
              content: SizedBox(
                width: 300,
                height: 200,
                child: Column(
                  children: [
                    DropdownButtonFormField(
                      // 显示选择结果
                      value: dropList.first,
                      // 生成结果
                      items: dropList.map<DropdownMenuItem<String>>((String value) {
                        return DropdownMenuItem<String>(
                          value: value,
                          child: Text(value, textAlign: TextAlign.center),
                        );
                      }).toList(),
                      // 按钮菜单选择回调
                      onChanged: (String? value) {
                        setState(() {
                          _forgetshowContent = value!;
                        });
                      },
                      isDense: true,
                      style: TextStyle(color: Colors.grey.shade600,),
                      iconEnabledColor:Colors.grey.shade600,
                      iconDisabledColor: Colors.grey.shade600,
                    ),
                    TextField(
                      controller: _newusername2,
                      decoration: const InputDecoration(hintText: "用户名"),
                      onChanged: (newuser) {
                        //获取用户名
                        _forgetNewUsername = newuser;
                      },
                    ),
                    TextField(
                      controller: _newpwd2,
                      decoration: const InputDecoration(hintText: "密码"),
                      onChanged: (newpwd) {
                        //获取用户名
                        _forgetNewPwd = newpwd;
                      },
                    ),
                  ],
                ),
              ),

              actions: <Widget>[
                MaterialButton(
                  color: Colors.teal,
                  child: const Text('取消'),
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                ),
                MaterialButton(
                  color: Colors.teal,
                  child: const Text('修改密码'),
                  onPressed: () {
                    if(_forgetNewUsername!="" && _forgetNewPwd!="" && _forgetshowContent!="" && _forgetshowContent!=dropList[0]){
                      querysampleDetail();
                      if(_trusthim){
                        Fluttertoast.showToast(
                          msg: "修改成功,新密码为:${_forgetNewPwd}",
                          toastLength: Toast.LENGTH_SHORT,
                          gravity: ToastGravity.BOTTOM,
                        );
                        _trusthim = false;
                        Navigator.of(context).pop();
                      }else{
                        Fluttertoast.showToast(
                          msg: "不存在该用户!",
                          toastLength: Toast.LENGTH_SHORT,
                          gravity: ToastGravity.BOTTOM,
                        );
                      }
                    }else{
                      Fluttertoast.showToast(
                        msg: "信息为空,请重新输入",
                        toastLength: Toast.LENGTH_SHORT,
                        gravity: ToastGravity.BOTTOM,
                      );
                    }
                  },
                ),
              ],
            );
          });
    }


    Widget bottomArea = Container(
      margin: EdgeInsets.only(right: 20,left: 30),
      child: Row(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          TextButton(
            child: Text(
              "忘记密码?",
              style: TextStyle(
                color: Colors.blue[400],
                fontSize: 16.0,
              ),
            ),
            //忘记密码按钮,点击执行事件
            onPressed: ()=>forget(context),
          ),
          TextButton(
            child: Text(
              "快速注册",
              style: TextStyle(
                color: Colors.blue[400],
                fontSize: 16.0,
              ),
            ),
            //点击快速注册、执行事件
            onPressed: ()=>fastregister(context),
          )
        ],
      ),
    );


    void _pushmyself() {
      // 入栈
      Navigator.of(context).push(
        MaterialPageRoute<void>(
          builder: (BuildContext context) {
            return myself();
          },
        ),
      );
    };


    return Scaffold(
      backgroundColor: Colors.grey.shade100,
      // 外层添加一个手势,用于点击空白部分,回收键盘
      body: GestureDetector(
        onTap: (){
          // 点击空白区域,回收键盘
          print("点击了空白区域");
        },
        child: ListView(
          children: <Widget>[
            SizedBox(height: ScreenUtil().setHeight(80),),
            logoImageArea,
            SizedBox(height: ScreenUtil().setHeight(70),),
            inputTextArea,
            SizedBox(height: ScreenUtil().setHeight(80),),
            loginButtonArea,
            SizedBox(height: ScreenUtil().setHeight(60),),
            thirdLoginArea,
            SizedBox(height: ScreenUtil().setHeight(60),),
            bottomArea,
            SizedBox(height: ScreenUtil().setHeight(60),),
            Container(
              height: 20.0,
              child: ElevatedButton(
                // textColor: Colors.black,
                child: Text("创建数据库表"),
                onPressed: cratedb_table,
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(16.0),
              child: Text('具体结果是:$_data'),
            ),
          ],
        ),
      ),
      floatingActionButton:FloatingActionButton(
        onPressed: _pushmyself,
        // 悬浮符号的符号
        child: const Icon(Icons.fingerprint),
      ),
      // 悬浮符号放中间
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
    );
  }
}


Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐