4 changed files with 850 additions and 453 deletions
Split View
Diff Options
-
4lib/main.dart
-
222lib/pages/mine/user_info_controller.dart
-
837lib/pages/mine/user_info_page.dart
-
240pubspec.lock
@ -0,0 +1,222 @@ |
|||
import 'dart:io'; |
|||
import 'package:flutter/cupertino.dart'; |
|||
import 'package:get/get.dart'; |
|||
import 'package:get_storage/get_storage.dart'; |
|||
import 'package:flutter/material.dart'; |
|||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; |
|||
import 'package:image_picker/image_picker.dart'; |
|||
|
|||
class UserInfoController extends GetxController { |
|||
// 用户信息表单字段 |
|||
final gender = 'male'.obs; // 默认选择男性 |
|||
final nickname = ''.obs; |
|||
final birthday = ''.obs; |
|||
final education = ''.obs; |
|||
final invitationCode = ''.obs; |
|||
final avatarUrl = ''.obs; |
|||
|
|||
// 加载状态 |
|||
final isSubmitting = false.obs; |
|||
|
|||
// GetStorage实例,用于存储用户信息 |
|||
final storage = GetStorage(); |
|||
|
|||
// 选择性别 |
|||
void selectGender(String selectedGender) { |
|||
gender.value = selectedGender; |
|||
// 打印选择的性别 |
|||
print('选择的性别: $selectedGender'); |
|||
// 显示选择结果 |
|||
SmartDialog.showToast('已选择${selectedGender == 'male' ? '男' : '女'}性'); |
|||
} |
|||
|
|||
// 选择日期 |
|||
void selectBirthday(String selectedDate) { |
|||
birthday.value = selectedDate; |
|||
// 打印选择的日期 |
|||
print('选择的出生日期: $selectedDate'); |
|||
// 显示选择结果 |
|||
SmartDialog.showToast('出生日期已选择'); |
|||
} |
|||
|
|||
// 选择学历 |
|||
void selectEducation(String selectedEducation) { |
|||
education.value = selectedEducation; |
|||
// 打印选择的学历 |
|||
print('选择的学历: $selectedEducation'); |
|||
// 显示选择结果 |
|||
SmartDialog.showToast('学历已选择'); |
|||
|
|||
|
|||
} |
|||
|
|||
// 选择头像 - 业务逻辑处理 |
|||
Future<void> handleCameraCapture() async { |
|||
try { |
|||
// 请求相机权限并拍照 |
|||
final ImagePicker picker = ImagePicker(); |
|||
final XFile? photo = await picker.pickImage(source: ImageSource.camera); |
|||
|
|||
if (photo != null) { |
|||
await processSelectedImage(File(photo.path)); |
|||
} |
|||
} catch (e) { |
|||
print('拍照失败: $e'); |
|||
// 更友好的错误提示 |
|||
if (e.toString().contains('permission') || e.toString().contains('权限')) { |
|||
SmartDialog.showToast('相机权限被拒绝,请在设置中允许访问相机'); |
|||
} else if (e.toString().contains('camera') || e.toString().contains('相机')) { |
|||
SmartDialog.showToast('设备没有可用的相机'); |
|||
} else { |
|||
SmartDialog.showToast('拍照失败,请重试'); |
|||
} |
|||
} |
|||
} |
|||
|
|||
Future<void> handleGallerySelection() async { |
|||
try { |
|||
// 从相册选择图片 |
|||
final ImagePicker picker = ImagePicker(); |
|||
final XFile? image = await picker.pickImage(source: ImageSource.gallery); |
|||
|
|||
if (image != null) { |
|||
await processSelectedImage(File(image.path)); |
|||
} |
|||
} catch (e) { |
|||
print('选择图片失败: $e'); |
|||
// 更友好的错误提示 |
|||
if (e.toString().contains('permission') || e.toString().contains('权限')) { |
|||
SmartDialog.showToast('相册权限被拒绝,请在设置中允许访问相册'); |
|||
} else { |
|||
SmartDialog.showToast('选择图片失败,请重试'); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 处理选中的图片 |
|||
Future<void> processSelectedImage(File imageFile) async { |
|||
try { |
|||
// 显示加载提示 |
|||
SmartDialog.showLoading(msg: '正在处理头像...'); |
|||
|
|||
// 更新本地头像URL(实际项目中应该先上传到服务器) |
|||
// 这里直接使用本地文件路径作为临时URL |
|||
avatarUrl.value = imageFile.path; |
|||
|
|||
// 保存到本地存储 |
|||
final currentUserInfo = storage.read('userInfo') ?? {}; |
|||
if (currentUserInfo is Map<String, dynamic>) { |
|||
currentUserInfo['avatarUrl'] = imageFile.path; |
|||
await storage.write('userInfo', currentUserInfo); |
|||
} |
|||
|
|||
SmartDialog.dismiss(); |
|||
SmartDialog.showToast('头像设置成功'); |
|||
} catch (e) { |
|||
SmartDialog.dismiss(); |
|||
print('处理图片失败: $e'); |
|||
SmartDialog.showToast('处理图片失败'); |
|||
} |
|||
} |
|||
|
|||
// 选择头像入口方法(保持兼容性) |
|||
void selectAvatar() { |
|||
// 这个方法现在只是一个入口,实际的UI交互在页面中实现 |
|||
// 页面会调用上面的具体处理方法 |
|||
} |
|||
|
|||
// 验证表单 |
|||
bool _validateForm() { |
|||
// 验证昵称 |
|||
if (nickname.value.isEmpty) { |
|||
SmartDialog.showToast('请输入昵称'); |
|||
return false; |
|||
} |
|||
|
|||
// 验证生日 |
|||
if (birthday.value.isEmpty) { |
|||
SmartDialog.showToast('请选择出生日期'); |
|||
return false; |
|||
} |
|||
|
|||
// 验证学历 |
|||
if (education.value.isEmpty) { |
|||
SmartDialog.showToast('请选择学历'); |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
// 构建提交参数 |
|||
Map<String, dynamic> _buildSubmitParams() { |
|||
return { |
|||
'gender': gender.value == 'male' ? 1 : 2, // 1:男, 2:女 |
|||
'nickname': nickname.value, |
|||
'birthday': birthday.value, |
|||
'education': education.value, |
|||
if (invitationCode.value.isNotEmpty) 'invitationCode': invitationCode.value, |
|||
if (avatarUrl.value.isNotEmpty) 'avatarUrl': avatarUrl.value, |
|||
}; |
|||
} |
|||
|
|||
// 提交用户信息 |
|||
Future<void> submitUserInfo() async { |
|||
// 验证表单 |
|||
if (!_validateForm()) { |
|||
return; |
|||
} |
|||
|
|||
isSubmitting.value = true; |
|||
|
|||
try { |
|||
// 构建请求参数 |
|||
final params = _buildSubmitParams(); |
|||
|
|||
// 调用UserApi中的完善用户信息接口 |
|||
// 注意:这里需要在UserApi中添加updateUserInfo方法 |
|||
// 由于目前没有看到完整的API定义,这里先模拟成功 |
|||
// 实际项目中应该调用真实的API |
|||
|
|||
// 模拟网络延迟 |
|||
await Future.delayed(const Duration(seconds: 1)); |
|||
|
|||
// 打印提交的信息 |
|||
print('提交用户信息参数: $params'); |
|||
|
|||
// 模拟成功响应 |
|||
// final response = await _userApi.updateUserInfo(params); |
|||
|
|||
// 处理响应 |
|||
// if (response.data.isSuccess) { |
|||
// 更新本地存储的用户信息 |
|||
final currentUserInfo = storage.read('userInfo') ?? {}; |
|||
if (currentUserInfo is Map<String, dynamic>) { |
|||
currentUserInfo.addAll({ |
|||
'gender': gender.value, |
|||
'nickname': nickname.value, |
|||
'birthday': birthday.value, |
|||
'education': education.value, |
|||
}); |
|||
await storage.write('userInfo', currentUserInfo); |
|||
} |
|||
|
|||
// 显示成功提示 |
|||
SmartDialog.showToast('信息提交成功!'); |
|||
// 延迟后跳转 |
|||
Future.delayed(const Duration(milliseconds: 1500), () { |
|||
// 跳转到主页面(暂时注释,实际使用时需要导入并替换正确的路由) |
|||
// Get.offAllNamed('/main'); |
|||
}); |
|||
// } else { |
|||
// Get.snackbar('错误', response.data.message); |
|||
// } |
|||
} catch (e) { |
|||
print('提交用户信息失败: $e'); |
|||
// 显示错误提示 |
|||
SmartDialog.showToast('提交失败,请重试'); |
|||
} finally { |
|||
isSubmitting.value = false; |
|||
} |
|||
} |
|||
} |
|||
@ -1,393 +1,566 @@ |
|||
import 'dart:io'; |
|||
import 'package:flutter/material.dart'; |
|||
import 'package:flutter/cupertino.dart'; |
|||
import 'package:dating_touchme_app/generated/assets.dart'; |
|||
import 'package:get/get.dart'; |
|||
import 'user_info_controller.dart'; |
|||
|
|||
class UserInfoPage extends StatefulWidget { |
|||
class UserInfoPage extends StatelessWidget { |
|||
const UserInfoPage({Key? key}) : super(key: key); |
|||
|
|||
@override |
|||
State<UserInfoPage> createState() => _UserInfoPageState(); |
|||
} |
|||
|
|||
class _UserInfoPageState extends State<UserInfoPage> { |
|||
String _gender = 'male'; // 默认选择男性 |
|||
String _nickname = '强壮的瘦子'; |
|||
String _birthday = ''; |
|||
String _education = ''; |
|||
String _invitationCode = ''; |
|||
// 显示头像选择选项 |
|||
void _showAvatarOptions(UserInfoController controller) { |
|||
showCupertinoModalPopup( |
|||
context: Get.context!, |
|||
builder: (context) => CupertinoActionSheet( |
|||
title: const Text('选择头像'), |
|||
actions: <Widget>[ |
|||
CupertinoActionSheetAction( |
|||
child: const Text('拍照'), |
|||
onPressed: () async { |
|||
Navigator.pop(context); |
|||
await controller.handleCameraCapture(); |
|||
}, |
|||
), |
|||
CupertinoActionSheetAction( |
|||
child: const Text('从相册选择'), |
|||
onPressed: () async { |
|||
Navigator.pop(context); |
|||
await controller.handleGallerySelection(); |
|||
}, |
|||
), |
|||
], |
|||
cancelButton: CupertinoActionSheetAction( |
|||
child: const Text('取消'), |
|||
isDestructiveAction: true, |
|||
onPressed: () { |
|||
Navigator.pop(context); |
|||
}, |
|||
), |
|||
), |
|||
); |
|||
} |
|||
|
|||
@override |
|||
Widget build(BuildContext context) { |
|||
return Scaffold( |
|||
body: Stack( |
|||
children: [ |
|||
// 背景图 |
|||
Positioned.fill( |
|||
child: Image.asset( |
|||
Assets.imagesBgInformation, |
|||
fit: BoxFit.cover, |
|||
), |
|||
// 显示学历选择弹框 |
|||
void _showEducationPicker(UserInfoController controller) { |
|||
final List<String> educationOptions = ['大专以下', '大专', '本科', '硕士及以上']; |
|||
|
|||
showModalBottomSheet( |
|||
context: Get.context!, |
|||
shape: const RoundedRectangleBorder( |
|||
borderRadius: BorderRadius.only( |
|||
topLeft: Radius.circular(8), |
|||
topRight: Radius.circular(8), |
|||
), |
|||
), |
|||
builder: (BuildContext context) { |
|||
return Container( |
|||
padding: const EdgeInsets.all(16), |
|||
decoration: BoxDecoration( |
|||
color: Colors.white, // 明确设置背景色 |
|||
borderRadius: const BorderRadius.only( |
|||
topLeft: Radius.circular(8), |
|||
topRight: Radius.circular(8), |
|||
), |
|||
), |
|||
child: Column( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: [ |
|||
// 标题和关闭按钮 |
|||
Stack( |
|||
alignment: Alignment.center, |
|||
children: [ |
|||
// 关闭按钮 - 左对齐 |
|||
Align( |
|||
alignment: Alignment.centerLeft, |
|||
child: IconButton( |
|||
icon: const Icon(Icons.close), |
|||
onPressed: () { |
|||
Navigator.pop(context); |
|||
}, |
|||
), |
|||
), |
|||
// 标题 - 居中 |
|||
Text( |
|||
'学历', |
|||
style: const TextStyle( |
|||
fontSize: 18, |
|||
fontWeight: FontWeight.bold, |
|||
), |
|||
// 内容区域 |
|||
SafeArea( |
|||
child: SingleChildScrollView( |
|||
padding: const EdgeInsets.symmetric(horizontal: 20.0), |
|||
child: Column( |
|||
children: [ |
|||
// 标题 |
|||
const SizedBox(height: 20), |
|||
Text( |
|||
'完善信息', |
|||
style: TextStyle( |
|||
fontSize: 24, |
|||
fontWeight: FontWeight.bold, |
|||
color: Color.fromRGBO(51, 51, 51, 1), |
|||
), |
|||
], |
|||
), |
|||
const SizedBox(height: 16), |
|||
|
|||
// 学历选项列表 |
|||
for (String education in educationOptions) |
|||
Container( |
|||
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), // 左右10,上下6 |
|||
child: ElevatedButton( |
|||
style: ElevatedButton.styleFrom( |
|||
backgroundColor: controller.education.value == education |
|||
? const Color.fromRGBO(123, 104, 238, 1) // 紫色 |
|||
: const Color.fromRGBO(247, 247, 247, 1), |
|||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 25), // 增加水平内边距 |
|||
minimumSize: const Size(double.infinity, 48), // 宽度充满,最小高度48 |
|||
shape: RoundedRectangleBorder( |
|||
borderRadius: BorderRadius.circular(32), |
|||
), |
|||
elevation: 0, |
|||
), |
|||
onPressed: () { |
|||
Navigator.pop(context); |
|||
controller.selectEducation(education); |
|||
}, |
|||
child: Text( |
|||
education, |
|||
style: TextStyle( |
|||
color: controller.education.value == education ? Colors.white : Colors.black, |
|||
fontSize: 16, |
|||
), |
|||
), |
|||
), |
|||
const SizedBox(height: 30), |
|||
|
|||
// 头像 |
|||
Stack( |
|||
), |
|||
|
|||
// 底部间距 |
|||
const SizedBox(height: 20), |
|||
], |
|||
), |
|||
); |
|||
}, |
|||
); |
|||
} |
|||
|
|||
// 显示日期选择器 |
|||
void _showDatePicker(UserInfoController controller) { |
|||
// 计算最小和最大日期 |
|||
final now = DateTime.now(); |
|||
final maxDate = DateTime(now.year - 18); // 最小18岁 |
|||
final minDate = DateTime(now.year - 80); // 最大80岁 |
|||
|
|||
// 初始选择日期(默认为25岁) |
|||
DateTime initialDate = DateTime(now.year - 25); |
|||
if (controller.birthday.value.isNotEmpty) { |
|||
try { |
|||
final List<String> dateParts = controller.birthday.value.split('-'); |
|||
if (dateParts.length == 3) { |
|||
initialDate = DateTime( |
|||
int.parse(dateParts[0]), |
|||
int.parse(dateParts[1]), |
|||
int.parse(dateParts[2]), |
|||
); |
|||
// 确保初始日期在有效范围内 |
|||
if (initialDate.isBefore(minDate)) initialDate = minDate; |
|||
if (initialDate.isAfter(maxDate)) initialDate = maxDate; |
|||
} |
|||
} catch (e) { |
|||
print('解析日期失败: $e'); |
|||
} |
|||
} |
|||
|
|||
// 临时存储选择的日期 |
|||
DateTime? selectedDate = initialDate; |
|||
|
|||
showCupertinoModalPopup( |
|||
context: Get.context!, |
|||
builder: (BuildContext context) { |
|||
return Container( |
|||
height: 300, |
|||
color: CupertinoColors.white, |
|||
child: Column( |
|||
children: [ |
|||
// 头部按钮区域 |
|||
Container( |
|||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), |
|||
child: Row( |
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|||
children: [ |
|||
CupertinoButton( |
|||
child: const Text('取消'), |
|||
onPressed: () { |
|||
Navigator.pop(context); |
|||
}, |
|||
), |
|||
CupertinoButton( |
|||
child: const Text('确定'), |
|||
onPressed: () { |
|||
Navigator.pop(context); |
|||
if (selectedDate != null) { |
|||
// 格式化为YYYY-MM-DD |
|||
final formattedDate = '${selectedDate!.year}-' |
|||
'${selectedDate!.month.toString().padLeft(2, '0')}-' |
|||
'${selectedDate!.day.toString().padLeft(2, '0')}'; |
|||
controller.selectBirthday(formattedDate); |
|||
} |
|||
}, |
|||
), |
|||
], |
|||
), |
|||
), |
|||
// 日期选择器 |
|||
Expanded( |
|||
child: CupertinoDatePicker( |
|||
mode: CupertinoDatePickerMode.date, |
|||
initialDateTime: initialDate, |
|||
minimumDate: minDate, |
|||
maximumDate: maxDate, |
|||
onDateTimeChanged: (DateTime dateTime) { |
|||
selectedDate = dateTime; |
|||
}, |
|||
use24hFormat: true, |
|||
backgroundColor: CupertinoColors.white, |
|||
), |
|||
), |
|||
], |
|||
), |
|||
); |
|||
}, |
|||
); |
|||
} |
|||
|
|||
@override |
|||
Widget build(BuildContext context) { |
|||
return GetX<UserInfoController>( |
|||
init: UserInfoController(), |
|||
builder: (controller) { |
|||
return Scaffold( |
|||
body: Stack( |
|||
children: [ |
|||
// 背景图 |
|||
Positioned.fill( |
|||
child: Image.asset( |
|||
Assets.imagesBgInformation, |
|||
fit: BoxFit.cover, |
|||
), |
|||
), |
|||
// 内容区域 |
|||
SafeArea( |
|||
child: SingleChildScrollView( |
|||
padding: const EdgeInsets.symmetric(horizontal: 20.0), |
|||
child: Column( |
|||
children: [ |
|||
Container( |
|||
width: 85, |
|||
height: 85, |
|||
decoration: const BoxDecoration( |
|||
shape: BoxShape.circle, |
|||
color: Colors.grey, |
|||
// 标题 |
|||
const SizedBox(height: 20), |
|||
const Text( |
|||
'完善信息', |
|||
style: TextStyle( |
|||
fontSize: 20, |
|||
fontWeight: FontWeight.bold, |
|||
color: Color.fromRGBO(51, 51, 51, 1), |
|||
), |
|||
child: ClipOval( |
|||
// 这里可以替换为实际的头像图片 |
|||
child: Image.asset( |
|||
Assets.imagesAvatarsExample, |
|||
fit: BoxFit.cover, |
|||
), |
|||
const SizedBox(height: 25), |
|||
|
|||
// 头像 |
|||
GestureDetector( |
|||
onTap: () => _showAvatarOptions(controller), |
|||
child: Stack( |
|||
children: [ |
|||
Container( |
|||
width: 85, |
|||
height: 85, |
|||
decoration: const BoxDecoration( |
|||
shape: BoxShape.circle, |
|||
color: Colors.grey, |
|||
), |
|||
child: ClipOval( |
|||
// 根据avatarUrl显示头像,如果为空则显示默认图片 |
|||
child: controller.avatarUrl.value.isNotEmpty |
|||
? Image.file( |
|||
File(controller.avatarUrl.value), |
|||
fit: BoxFit.cover, |
|||
width: 85, |
|||
height: 85, |
|||
) |
|||
: Image.asset( |
|||
Assets.imagesAvatarsExample, |
|||
fit: BoxFit.cover, |
|||
), |
|||
), |
|||
), |
|||
Positioned( |
|||
bottom: 0, |
|||
right: 0, |
|||
child: Container( |
|||
width: 20, |
|||
height: 20, |
|||
child: Stack( |
|||
children: [ |
|||
Center( |
|||
child: Image.asset( |
|||
Assets.imagesBgEditAvatars, |
|||
), |
|||
), |
|||
Center( |
|||
child: Image.asset( |
|||
Assets.imagesEditAvatarsIcon, |
|||
width: 12, |
|||
height: 12, |
|||
), |
|||
), |
|||
], |
|||
), |
|||
), |
|||
), |
|||
], |
|||
), |
|||
), |
|||
const SizedBox(height: 25), |
|||
|
|||
// 性别选择 |
|||
const Align( |
|||
alignment: Alignment.centerLeft, |
|||
child: Text( |
|||
'性别 (注册后不可修改)', |
|||
style: TextStyle( |
|||
fontSize: 15, |
|||
color: Color.fromRGBO(144, 144, 144, 1), |
|||
fontWeight: FontWeight.w500, |
|||
), |
|||
), |
|||
), |
|||
Positioned( |
|||
bottom: 0, |
|||
right: 0, |
|||
child: Container( |
|||
width: 30, |
|||
height: 30, |
|||
decoration: const BoxDecoration( |
|||
shape: BoxShape.circle, |
|||
color: Colors.blue, |
|||
const SizedBox(height: 10), |
|||
Row( |
|||
children: [ |
|||
GestureDetector( |
|||
onTap: () => controller.selectGender('male'), |
|||
child: Container( |
|||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.circular(20), |
|||
color: controller.gender.value == 'male' ? Colors.black : Colors.grey[200], |
|||
), |
|||
child: Row( |
|||
children: [ |
|||
Image.asset( |
|||
Assets.imagesManIcon, |
|||
width: 20, |
|||
height: 20, |
|||
color: controller.gender.value == 'male' ? Colors.white : Colors.black, |
|||
), |
|||
const SizedBox(width: 5), |
|||
], |
|||
), |
|||
), |
|||
), |
|||
child: Image.asset( |
|||
Assets.imagesBgEditAvatars, |
|||
width: 16, |
|||
height: 16, |
|||
color: Colors.white, |
|||
const SizedBox(width: 20), |
|||
GestureDetector( |
|||
onTap: () => controller.selectGender('female'), |
|||
child: Container( |
|||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.circular(20), |
|||
color: controller.gender.value == 'female' ? Colors.pink : Colors.grey[200], |
|||
), |
|||
child: Row( |
|||
children: [ |
|||
Image.asset( |
|||
Assets.imagesWomenIcon, |
|||
width: 20, |
|||
height: 20, |
|||
color: controller.gender.value == 'female' ? Colors.white : Colors.black, |
|||
), |
|||
const SizedBox(width: 5), |
|||
], |
|||
), |
|||
), |
|||
), |
|||
], |
|||
), |
|||
const SizedBox(height: 25), |
|||
|
|||
// 昵称 |
|||
const Align( |
|||
alignment: Alignment.centerLeft, |
|||
child: Text( |
|||
'昵称', |
|||
style: TextStyle( |
|||
fontSize: 15, |
|||
color: Color.fromRGBO(144, 144, 144, 1), |
|||
fontWeight: FontWeight.w500, |
|||
), |
|||
), |
|||
), |
|||
], |
|||
), |
|||
const SizedBox(height: 30), |
|||
|
|||
// 性别选择 |
|||
const Align( |
|||
alignment: Alignment.centerLeft, |
|||
child: Text( |
|||
'性别 (注册后不可修改)', |
|||
style: TextStyle( |
|||
fontSize: 16, |
|||
color: Color.fromRGBO(144, 144, 144, 1), |
|||
fontWeight: FontWeight.w500, |
|||
const SizedBox(height: 10), |
|||
Container( |
|||
padding: const EdgeInsets.symmetric(horizontal: 16), |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.circular(32), |
|||
color: Color.fromRGBO(247, 247, 247, 1), |
|||
), |
|||
child: Row( |
|||
children: [ |
|||
Expanded( |
|||
child: TextField( |
|||
controller: TextEditingController(text: controller.nickname.value), |
|||
onChanged: (value) { |
|||
controller.nickname.value = value; |
|||
}, |
|||
decoration: const InputDecoration( |
|||
border: InputBorder.none, |
|||
hintText: '请输入昵称', |
|||
hintStyle: TextStyle(color: Colors.grey), |
|||
), |
|||
), |
|||
), |
|||
], |
|||
), |
|||
), |
|||
), |
|||
), |
|||
const SizedBox(height: 10), |
|||
Row( |
|||
children: [ |
|||
const SizedBox(height: 25), |
|||
|
|||
// 出生日期 |
|||
const Align( |
|||
alignment: Alignment.centerLeft, |
|||
child: Text( |
|||
'年龄', |
|||
style: TextStyle( |
|||
fontSize: 15, |
|||
color: Color.fromRGBO(144, 144, 144, 1), |
|||
fontWeight: FontWeight.w500, |
|||
), |
|||
), |
|||
), |
|||
const SizedBox(height: 10), |
|||
GestureDetector( |
|||
onTap: () { |
|||
setState(() { |
|||
_gender = 'male'; |
|||
}); |
|||
// 显示Cupertino日期选择器 |
|||
_showDatePicker(controller); |
|||
}, |
|||
child: Container( |
|||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), |
|||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.circular(20), |
|||
color: _gender == 'male' ? Colors.black : Colors.grey[200], |
|||
borderRadius: BorderRadius.circular(32), |
|||
color: Color.fromRGBO(247, 247, 247, 1), |
|||
), |
|||
child: Row( |
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|||
children: [ |
|||
Image.asset( |
|||
Assets.imagesManIcon, |
|||
width: 20, |
|||
height: 20, |
|||
color: _gender == 'male' ? Colors.white : Colors.black, |
|||
Text( |
|||
controller.birthday.value.isEmpty ? '请选择你的出生日期' : controller.birthday.value, |
|||
style: TextStyle( |
|||
color: controller.birthday.value.isEmpty ? Colors.grey : Colors.black, |
|||
), |
|||
), |
|||
const SizedBox(width: 5), |
|||
const Icon(Icons.arrow_forward_ios, color: Colors.grey), |
|||
], |
|||
), |
|||
), |
|||
), |
|||
const SizedBox(width: 20), |
|||
const SizedBox(height: 25), |
|||
|
|||
// 学历 |
|||
const Align( |
|||
alignment: Alignment.centerLeft, |
|||
child: Text( |
|||
'学历', |
|||
style: TextStyle( |
|||
fontSize: 15, |
|||
color: Color.fromRGBO(144, 144, 144, 1), |
|||
fontWeight: FontWeight.w500, |
|||
), |
|||
), |
|||
), |
|||
const SizedBox(height: 10), |
|||
GestureDetector( |
|||
onTap: () { |
|||
setState(() { |
|||
_gender = 'female'; |
|||
}); |
|||
// 显示学历选择弹框 |
|||
_showEducationPicker(controller); |
|||
}, |
|||
child: Container( |
|||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), |
|||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.circular(20), |
|||
color: _gender == 'female' ? Colors.pink : Colors.grey[200], |
|||
borderRadius: BorderRadius.circular(32), |
|||
color: Color.fromRGBO(247, 247, 247, 1), |
|||
), |
|||
child: Row( |
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|||
children: [ |
|||
Image.asset( |
|||
Assets.imagesWomenIcon, |
|||
width: 20, |
|||
height: 20, |
|||
color: _gender == 'female' ? Colors.white : Colors.black, |
|||
Text( |
|||
controller.education.value.isEmpty ? '请选择你的学历' : controller.education.value, |
|||
style: TextStyle( |
|||
color: controller.education.value.isEmpty ? Colors.grey : Colors.black, |
|||
), |
|||
), |
|||
const SizedBox(width: 5), |
|||
const Icon(Icons.arrow_forward_ios, color: Colors.grey), |
|||
], |
|||
), |
|||
), |
|||
), |
|||
], |
|||
), |
|||
const SizedBox(height: 30), |
|||
|
|||
// 昵称 |
|||
const Align( |
|||
alignment: Alignment.centerLeft, |
|||
child: Text( |
|||
'昵称', |
|||
style: TextStyle( |
|||
fontSize: 16, |
|||
color: Colors.black, |
|||
fontWeight: FontWeight.w500, |
|||
), |
|||
), |
|||
), |
|||
const SizedBox(height: 10), |
|||
Container( |
|||
padding: const EdgeInsets.symmetric(horizontal: 16), |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.circular(8), |
|||
color: Colors.white, |
|||
), |
|||
child: Row( |
|||
children: [ |
|||
Expanded( |
|||
child: TextField( |
|||
controller: TextEditingController(text: _nickname), |
|||
onChanged: (value) { |
|||
_nickname = value; |
|||
}, |
|||
decoration: const InputDecoration( |
|||
border: InputBorder.none, |
|||
), |
|||
const SizedBox(height: 25), |
|||
|
|||
// 邀请码 |
|||
const Align( |
|||
alignment: Alignment.centerLeft, |
|||
child: Text( |
|||
'邀请码 (非必填)', |
|||
style: TextStyle( |
|||
fontSize: 15, |
|||
color: Color.fromRGBO(144, 144, 144, 1), |
|||
fontWeight: FontWeight.w500, |
|||
), |
|||
), |
|||
TextButton( |
|||
onPressed: () { |
|||
// 随机昵称功能(不需要实现) |
|||
), |
|||
const SizedBox(height: 10), |
|||
Container( |
|||
padding: const EdgeInsets.symmetric(horizontal: 16), |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.circular(32), |
|||
color: Color.fromRGBO(247, 247, 247, 1), |
|||
), |
|||
child: TextField( |
|||
onChanged: (value) { |
|||
controller.invitationCode.value = value; |
|||
}, |
|||
child: const Text( |
|||
'随机', |
|||
style: TextStyle( |
|||
color: Colors.grey, |
|||
), |
|||
decoration: const InputDecoration( |
|||
hintText: '请输入邀请码', |
|||
hintStyle: TextStyle(color: Colors.grey), |
|||
border: InputBorder.none, |
|||
), |
|||
), |
|||
], |
|||
), |
|||
), |
|||
const SizedBox(height: 30), |
|||
|
|||
// 出生日期 |
|||
const Align( |
|||
alignment: Alignment.centerLeft, |
|||
child: Text( |
|||
'年龄', |
|||
style: TextStyle( |
|||
fontSize: 16, |
|||
color: Colors.black, |
|||
fontWeight: FontWeight.w500, |
|||
), |
|||
), |
|||
), |
|||
const SizedBox(height: 10), |
|||
GestureDetector( |
|||
onTap: () { |
|||
// 打开日期选择器 |
|||
_selectDate(); |
|||
}, |
|||
child: Container( |
|||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.circular(8), |
|||
color: Colors.white, |
|||
), |
|||
child: Row( |
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|||
children: [ |
|||
Text( |
|||
_birthday.isEmpty ? '请选择你的出生日期' : _birthday, |
|||
style: TextStyle( |
|||
color: _birthday.isEmpty ? Colors.grey : Colors.black, |
|||
), |
|||
), |
|||
const Icon(Icons.arrow_forward_ios, color: Colors.grey), |
|||
], |
|||
), |
|||
), |
|||
), |
|||
const SizedBox(height: 30), |
|||
|
|||
// 学历 |
|||
const Align( |
|||
alignment: Alignment.centerLeft, |
|||
child: Text( |
|||
'学历', |
|||
style: TextStyle( |
|||
fontSize: 16, |
|||
color: Colors.black, |
|||
fontWeight: FontWeight.w500, |
|||
), |
|||
), |
|||
), |
|||
const SizedBox(height: 10), |
|||
GestureDetector( |
|||
onTap: () { |
|||
// 打开学历选择器 |
|||
_selectEducation(); |
|||
}, |
|||
child: Container( |
|||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.circular(8), |
|||
color: Colors.white, |
|||
), |
|||
child: Row( |
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|||
children: [ |
|||
Text( |
|||
_education.isEmpty ? '请选择你的学历' : _education, |
|||
style: TextStyle( |
|||
color: _education.isEmpty ? Colors.grey : Colors.black, |
|||
const SizedBox(height: 50), |
|||
|
|||
// 开始交友按钮 |
|||
SizedBox( |
|||
width: double.infinity, |
|||
height: 50, |
|||
child: ElevatedButton( |
|||
onPressed: controller.isSubmitting.value |
|||
? null |
|||
: controller.submitUserInfo, |
|||
style: ElevatedButton.styleFrom( |
|||
backgroundColor: Colors.blue, |
|||
shape: RoundedRectangleBorder( |
|||
borderRadius: BorderRadius.circular(25), |
|||
), |
|||
), |
|||
const Icon(Icons.arrow_forward_ios, color: Colors.grey), |
|||
], |
|||
), |
|||
), |
|||
), |
|||
const SizedBox(height: 30), |
|||
|
|||
// 邀请码 |
|||
const Align( |
|||
alignment: Alignment.centerLeft, |
|||
child: Text( |
|||
'邀请码 (非必填)', |
|||
style: TextStyle( |
|||
fontSize: 16, |
|||
color: Colors.black, |
|||
fontWeight: FontWeight.w500, |
|||
), |
|||
), |
|||
), |
|||
const SizedBox(height: 10), |
|||
Container( |
|||
padding: const EdgeInsets.symmetric(horizontal: 16), |
|||
decoration: BoxDecoration( |
|||
borderRadius: BorderRadius.circular(8), |
|||
color: Colors.white, |
|||
), |
|||
child: TextField( |
|||
onChanged: (value) { |
|||
_invitationCode = value; |
|||
}, |
|||
decoration: const InputDecoration( |
|||
hintText: '请输入邀请码', |
|||
hintStyle: TextStyle(color: Colors.grey), |
|||
border: InputBorder.none, |
|||
), |
|||
), |
|||
), |
|||
const SizedBox(height: 50), |
|||
|
|||
// 开始交友按钮 |
|||
SizedBox( |
|||
width: double.infinity, |
|||
height: 50, |
|||
child: ElevatedButton( |
|||
onPressed: () { |
|||
// 提交用户信息 |
|||
_submitUserInfo(); |
|||
}, |
|||
style: ElevatedButton.styleFrom( |
|||
backgroundColor: Colors.blue, |
|||
shape: RoundedRectangleBorder( |
|||
borderRadius: BorderRadius.circular(25), |
|||
), |
|||
), |
|||
child: const Text( |
|||
'开始交友', |
|||
style: TextStyle( |
|||
fontSize: 18, |
|||
color: Colors.white, |
|||
child: controller.isSubmitting.value |
|||
? const SizedBox( |
|||
width: 20, |
|||
height: 20, |
|||
child: CircularProgressIndicator( |
|||
color: Colors.white, |
|||
strokeWidth: 2, |
|||
), |
|||
) |
|||
: const Text( |
|||
'开始交友', |
|||
style: TextStyle( |
|||
fontSize: 18, |
|||
color: Colors.white, |
|||
), |
|||
), |
|||
), |
|||
), |
|||
), |
|||
const SizedBox(height: 30), |
|||
], |
|||
), |
|||
const SizedBox(height: 30), |
|||
], |
|||
), |
|||
), |
|||
), |
|||
], |
|||
), |
|||
], |
|||
), |
|||
); |
|||
} |
|||
|
|||
// 选择日期 |
|||
void _selectDate() { |
|||
// 这里可以实现日期选择逻辑 |
|||
// 为了简单起见,我们先设置一个默认日期 |
|||
setState(() { |
|||
_birthday = '1990-01-01'; |
|||
}); |
|||
} |
|||
|
|||
// 选择学历 |
|||
void _selectEducation() { |
|||
// 这里可以实现学历选择逻辑 |
|||
// 为了简单起见,我们先设置一个默认学历 |
|||
setState(() { |
|||
_education = '本科'; |
|||
}); |
|||
} |
|||
|
|||
// 提交用户信息 |
|||
void _submitUserInfo() { |
|||
// 这里可以实现提交逻辑 |
|||
print('提交用户信息:'); |
|||
print('性别: $_gender'); |
|||
print('昵称: $_nickname'); |
|||
print('生日: $_birthday'); |
|||
print('学历: $_education'); |
|||
print('邀请码: $_invitationCode'); |
|||
|
|||
// 可以添加验证逻辑 |
|||
if (_birthday.isEmpty || _education.isEmpty) { |
|||
ScaffoldMessenger.of(context).showSnackBar( |
|||
const SnackBar(content: Text('请完善所有必填信息')), |
|||
); |
|||
return; |
|||
} |
|||
|
|||
// 提交成功后跳转到下一个页面 |
|||
ScaffoldMessenger.of(context).showSnackBar( |
|||
const SnackBar(content: Text('信息提交成功')), |
|||
); |
|||
}, |
|||
); |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save