feat:增加登录模块
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:food_hub_app/profile.dart';
|
import 'package:food_hub_app/profile.dart';
|
||||||
import 'package:food_hub_app/record.dart';
|
import 'package:food_hub_app/record.dart';
|
||||||
|
import 'package:food_hub_app/views/login.dart';
|
||||||
|
import 'package:food_hub_app/views/recordForm.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
@@ -15,10 +17,10 @@ class MyApp extends StatelessWidget {
|
|||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
theme: ThemeData(fontFamily: 'CustomFont', primaryColor: Colors.green),
|
theme: ThemeData(fontFamily: 'CustomFont', primaryColor: Colors.green),
|
||||||
home: MainPage(),
|
home: LoginPage(),
|
||||||
routes: {
|
routes: {
|
||||||
'/home': (context) => MainPage(),
|
'/home': (context) => MainPage(),
|
||||||
'/new': (context) => NewPage(),
|
'/recordForm': (context) => RecordFormPage(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -28,10 +30,10 @@ class MainPage extends StatefulWidget {
|
|||||||
const MainPage({super.key});
|
const MainPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatefulWidget> createState() => _mainPage();
|
State<StatefulWidget> createState() => _MainPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _mainPage extends State<MainPage> {
|
class _MainPage extends State<MainPage> {
|
||||||
int _currentIndex = 0;
|
int _currentIndex = 0;
|
||||||
|
|
||||||
final List<Widget> _tabPages = const [RecordPage(), ProfilePage()];
|
final List<Widget> _tabPages = const [RecordPage(), ProfilePage()];
|
||||||
@@ -67,17 +69,7 @@ class _mainPage extends State<MainPage> {
|
|||||||
backgroundColor: Color(0xFFF5F5F5),
|
backgroundColor: Color(0xFFF5F5F5),
|
||||||
body: _tabPages[_currentIndex],
|
body: _tabPages[_currentIndex],
|
||||||
floatingActionButton:
|
floatingActionButton:
|
||||||
_currentIndex == _tabPages.length - 1
|
_currentIndex == _tabPages.length - 1 ? null : addItemButton(context),
|
||||||
? null
|
|
||||||
: FloatingActionButton(
|
|
||||||
mini: true,
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pushNamed(context, '/new');
|
|
||||||
},
|
|
||||||
backgroundColor: Colors.green,
|
|
||||||
shape: const CircleBorder(),
|
|
||||||
child: Icon(Icons.add, color: Colors.white),
|
|
||||||
),
|
|
||||||
bottomNavigationBar: BottomNavigationBar(
|
bottomNavigationBar: BottomNavigationBar(
|
||||||
currentIndex: _currentIndex,
|
currentIndex: _currentIndex,
|
||||||
iconSize: 25,
|
iconSize: 25,
|
||||||
@@ -99,23 +91,16 @@ class _mainPage extends State<MainPage> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NewPage extends StatelessWidget {
|
Widget addItemButton(BuildContext context) {
|
||||||
@override
|
void onAddItemClick(BuildContext context) {
|
||||||
Widget build(BuildContext context) {
|
Navigator.pushNamed(context, '/recordForm');
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(title: Text('新页面')),
|
|
||||||
body: Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Text('这是新页面'),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
child: Text('返回'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return FloatingActionButton(
|
||||||
|
mini: true,
|
||||||
|
onPressed: () => onAddItemClick(context),
|
||||||
|
backgroundColor: Colors.green,
|
||||||
|
shape: const CircleBorder(),
|
||||||
|
child: Icon(Icons.add, color: Colors.white),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
267
lib/views/login.dart
Normal file
267
lib/views/login.dart
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class LoginPage extends StatefulWidget {
|
||||||
|
const LoginPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => _LoginPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LoginPage extends State<LoginPage> {
|
||||||
|
final GlobalKey _formKey = GlobalKey<FormState>();
|
||||||
|
late String _username, _password;
|
||||||
|
bool _isObscure = true;
|
||||||
|
Color _eyeColor = Colors.grey;
|
||||||
|
final List _loginMethod = [
|
||||||
|
{"title": "phone", "icon": Icons.phone_android},
|
||||||
|
{"title": "email", "icon": Icons.email},
|
||||||
|
{"title": "wechat", "icon": Icons.wechat},
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
body: Form(
|
||||||
|
key: _formKey,
|
||||||
|
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// 可滚动的主要内容区域
|
||||||
|
Expanded(
|
||||||
|
child: ListView(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: kToolbarHeight),
|
||||||
|
buildTitle(),
|
||||||
|
const SizedBox(height: 60),
|
||||||
|
buildUsernameTextField(),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
buildPasswordTextField(context),
|
||||||
|
// 紧凑排列:记住密码在上,忘记密码在下,间距缩小
|
||||||
|
const SizedBox(height: 8), // 缩小密码框与记住密码的间距
|
||||||
|
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
buildRememberPasswordCheckbox(context), // 记住密码(左对齐)
|
||||||
|
buildForgetPasswordText(context),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 20), // 调整与登录按钮的间距
|
||||||
|
buildLoginButton(context),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// 固定在底部的其他登录选项区域
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 50),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
buildOtherLoginText(),
|
||||||
|
const SizedBox(height: 15),
|
||||||
|
buildOtherMethod(context),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
buildRegisterText(context),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildTitle() {
|
||||||
|
return const Text(
|
||||||
|
'食光集',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(fontSize: 42),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildUsernameTextField() {
|
||||||
|
return TextFormField(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: '账号',
|
||||||
|
prefixIcon: Icon(Icons.person),
|
||||||
|
hintText: "请输入账号",
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
filled: true,
|
||||||
|
fillColor: Colors.grey[100],
|
||||||
|
),
|
||||||
|
validator: (v) {
|
||||||
|
if (v!.isEmpty) {
|
||||||
|
return '请输入账号';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSaved: (v) => _username = v!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildPasswordTextField(BuildContext context) {
|
||||||
|
return TextFormField(
|
||||||
|
obscureText: _isObscure, // 是否显示文字
|
||||||
|
onSaved: (v) => _password = v!,
|
||||||
|
validator: (v) {
|
||||||
|
if (v!.isEmpty) {
|
||||||
|
return '请输入密码';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: "密码",
|
||||||
|
prefixIcon: Icon(Icons.lock),
|
||||||
|
hintText: "请输入密码",
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
filled: true,
|
||||||
|
fillColor: Colors.grey[100],
|
||||||
|
suffixIcon: IconButton(
|
||||||
|
icon: Icon(Icons.remove_red_eye, color: _eyeColor),
|
||||||
|
onPressed: () {
|
||||||
|
// 修改 state 内部变量, 且需要界面内容更新, 需要使用 setState()
|
||||||
|
setState(() {
|
||||||
|
_isObscure = !_isObscure;
|
||||||
|
_eyeColor =
|
||||||
|
(_isObscure
|
||||||
|
? Colors.grey
|
||||||
|
: Theme.of(context).iconTheme.color)!;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildRememberPasswordCheckbox(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Checkbox(
|
||||||
|
value: false,
|
||||||
|
onChanged: (bool? value) {
|
||||||
|
print("记住密码: $value");
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const Text('记住密码', style: TextStyle(color: Colors.grey, fontSize: 14)),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildForgetPasswordText(BuildContext context) {
|
||||||
|
return Align(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
child: TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
print("忘记密码");
|
||||||
|
},
|
||||||
|
child: const Text(
|
||||||
|
"忘记密码?",
|
||||||
|
style: TextStyle(fontSize: 14, color: Colors.grey),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildLoginButton(BuildContext context) {
|
||||||
|
return Align(
|
||||||
|
child: SizedBox(
|
||||||
|
height: 45,
|
||||||
|
width: double.infinity,
|
||||||
|
child: ElevatedButton(
|
||||||
|
style: ButtonStyle(
|
||||||
|
backgroundColor: WidgetStateProperty.all(Colors.green),
|
||||||
|
shape: WidgetStateProperty.all(
|
||||||
|
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'登录',
|
||||||
|
style: TextStyle(fontSize: 24, color: Colors.white),
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
// 表单校验通过才会继续执行
|
||||||
|
if ((_formKey.currentState as FormState).validate()) {
|
||||||
|
(_formKey.currentState as FormState).save();
|
||||||
|
Navigator.pushNamed(context, '/home');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildOtherLoginText() {
|
||||||
|
return SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
const Divider(color: Colors.grey, thickness: 0.5),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
color: Colors.white, // 与背景色一致,覆盖横线
|
||||||
|
child: const Text(
|
||||||
|
'其他方式登录',
|
||||||
|
style: TextStyle(color: Colors.grey, fontSize: 14),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildOtherMethod(context) {
|
||||||
|
return OverflowBar(
|
||||||
|
alignment: MainAxisAlignment.center,
|
||||||
|
children:
|
||||||
|
_loginMethod
|
||||||
|
.map(
|
||||||
|
(item) => Builder(
|
||||||
|
builder: (context) {
|
||||||
|
return IconButton(
|
||||||
|
icon: Icon(
|
||||||
|
item['icon'],
|
||||||
|
color: Theme.of(context).iconTheme.color,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
//TODO: 第三方登录方法
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text('${item['title']}登录'),
|
||||||
|
action: SnackBarAction(
|
||||||
|
label: '取消',
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildRegisterText(context) {
|
||||||
|
return Center(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const Text('没有账号?', style: TextStyle(fontSize: 18)),
|
||||||
|
GestureDetector(
|
||||||
|
child: const Text(
|
||||||
|
'点击注册',
|
||||||
|
style: TextStyle(fontSize: 18, color: Colors.green),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
print("点击注册");
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
lib/views/recordForm.dart
Normal file
25
lib/views/recordForm.dart
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class RecordFormPage extends StatelessWidget {
|
||||||
|
const RecordFormPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(title: Text('新页面'), backgroundColor: Colors.white),
|
||||||
|
backgroundColor: Color(0xFFF5F5F5),
|
||||||
|
body: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text('这是新页面'),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
child: Text('返回'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user