项目想法脱胎于2023年服务外包大赛A18题 随手买(详情)
整个APP思路如下:
这篇博客主要服务于登录界面,逻辑思路如下:
主要用的就是数据库的知识和界面设计的知识。
界面
点击指纹识别按钮查看作者信息
创建数据库
注册账号
修改密码
根据不同身份登录到不同界面(每个身份的子界面代码不在本章博客中)
依赖如下
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
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',
);
}
}
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
// print(dataList);
// String fun = "SELECT COUNT(*) FROM user WHERE username = '$_forgetNewUsername' AND kind = '$_forgetshowContent'";
//将数据放到集合里面显示
// List
// 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,
);
}
}