Browse Source

refactor(home): 优化主页布局和动画效果

- 将 SingleChildScrollView 替换为 Padding 以改善布局
- 实现自适应高度的耳机图片组件
- 为设备状态卡片添加平滑过渡动画
- 使用 AnimatedSwitcher 实现内容切换动画
- 优化热门AI体验部分的布局
newdev_shunjiawei
lxm 1 year ago
parent
commit
dac32e9188
  1. 153
      lib/modules/home/views/home_view.dart
  2. 2
      lib/modules/login/controllers/login_controller.dart

153
lib/modules/home/views/home_view.dart

@ -76,7 +76,7 @@ class HomeView extends GetView<HomeController> {
return Scaffold( return Scaffold(
backgroundColor: isDarkMode ? Colors.black : const Color(0xFFF9FAFC), backgroundColor: isDarkMode ? Colors.black : const Color(0xFFF9FAFC),
body: SafeArea( body: SafeArea(
child: SingleChildScrollView( child: Padding(
padding: EdgeInsets.all(16.w), padding: EdgeInsets.all(16.w),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -84,12 +84,12 @@ class HomeView extends GetView<HomeController> {
// 顶部标题栏 // 顶部标题栏
_buildAppBar(isDarkMode), _buildAppBar(isDarkMode),
// 顶部图片 // 可变高度的顶部图片区域
_buildEarbudsImage(), Obx(() => _buildAdaptiveEarbudsImage()),
SizedBox(height: 20.h), SizedBox(height: 20.h),
// 设备状态卡片 // 设备状态卡片 - 使用 AnimatedContainer 实现平滑过渡
IntroStepBuilder( IntroStepBuilder(
group: 'home', group: 'home',
order: 1, order: 1,
@ -107,7 +107,7 @@ class HomeView extends GetView<HomeController> {
}, },
builder: (BuildContext context, GlobalKey key) => SizedBox( builder: (BuildContext context, GlobalKey key) => SizedBox(
key: key, key: key,
child: _buildDeviceStatusCard(isDarkMode), child: _buildAnimatedDeviceStatusCard(isDarkMode),
), ),
), ),
@ -143,10 +143,17 @@ class HomeView extends GetView<HomeController> {
), ),
), ),
// 热门AI体验 // 热门AI体验 - 使用 Expanded 确保始终在可视范围内
_buildSectionTitle(isDarkMode), Expanded(
SizedBox(height: 16.h), child: Column(
_buildPremiumAILayout(), crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSectionTitle(isDarkMode),
SizedBox(height: 16.h),
Expanded(child: _buildPremiumAILayout()),
],
),
),
], ],
), ),
), ),
@ -196,70 +203,48 @@ class HomeView extends GetView<HomeController> {
); );
} }
// 耳机图片
Widget _buildEarbudsImage() {
// 自适应高度的耳机图片 - 根据设备连接状态动态调整高度
Widget _buildAdaptiveEarbudsImage() {
final bool isDarkMode = Get.isDarkMode; final bool isDarkMode = Get.isDarkMode;
return SizedBox( // 根据设备连接状态调整图片高度
height: 220.h, // 已连接时高度较小,为设备信息让出空间;未连接时高度较大
final double imageHeight = controller.isFullyConnectedRx.value ? 160.h : 220.h;
return AnimatedContainer(
duration: const Duration(milliseconds: 500), // 平滑过渡动画
curve: Curves.easeInOut,
height: imageHeight,
child: PageView( child: PageView(
children: [ children: [
// Center(
// child: ClipRRect(
// // 添加 ClipRRect 来实现圆角
// borderRadius: BorderRadius.circular(16.r), // 使用与其他部件一致的圆角大小
// child: SizedBox(
// width: double.infinity,
// height: 200.h,
// child: Image.asset(
// isDarkMode
// ? 'assets/images/robot_light.png'
// : 'assets/images/robot_light.png',
// fit: BoxFit.fitWidth,
// ),
// ),
// ),
// ),
Center( Center(
child: ClipRRect( child: ClipRRect(
// 添加 ClipRRect
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
child: Image.asset( child: Image.asset(
isDarkMode isDarkMode
? 'assets/images/headphone_new3.png' ? 'assets/images/headphone_new3.png'
: 'assets/images/headphone_new4.png', : 'assets/images/headphone_new4.png',
height: 220.h, height: imageHeight,
fit: BoxFit.contain, fit: BoxFit.contain,
), ),
), ),
), ),
// Center(
// child: ClipRRect(
// // 添加 ClipRRect
// borderRadius: BorderRadius.circular(16.r),
// child: SizedBox(
// width: double.infinity,
// height: 200.h,
// child: Image.asset(
// isDarkMode
// ? 'assets/images/glasses_light.png'
// : 'assets/images/glasses_light.png',
// fit: BoxFit.fitWidth,
// ),
// ),
// ),
// ),
], ],
), ),
); );
} }
// 设备状态卡片
Widget _buildDeviceStatusCard(bool isDarkMode) {
// 带动画的设备状态卡片 - 实现平滑的高度变化过渡
Widget _buildAnimatedDeviceStatusCard(bool isDarkMode) {
return Obx(() { return Obx(() {
// 使用连接状态作为key,强制在状态改变时重建widget
final isConnected = controller.isFullyConnectedRx.value; final isConnected = controller.isFullyConnectedRx.value;
return Container(
key: ValueKey('device_status_$isConnected'), return AnimatedContainer(
duration: const Duration(milliseconds: 500), // 平滑过渡动画
curve: Curves.easeInOut,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? const Color(0xFF1A1A1A) : Colors.white, color: isDarkMode ? const Color(0xFF1A1A1A) : Colors.white,
borderRadius: BorderRadius.circular(16.r), borderRadius: BorderRadius.circular(16.r),
@ -273,30 +258,58 @@ class HomeView extends GetView<HomeController> {
), ),
padding: EdgeInsets.fromLTRB(16.w, 16.h, 16.w, 16.h), padding: EdgeInsets.fromLTRB(16.w, 16.h, 16.w, 16.h),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, // 重要:让容器高度自适应内容
children: [ children: [
// 状态标题行 // 状态标题行
_buildDeviceStatusHeader(isDarkMode), _buildDeviceStatusHeader(isDarkMode),
// 设备信息 // 设备信息 - 使用 AnimatedSwitcher 实现内容切换动画
SizedBox(height: 12.h), SizedBox(height: 12.h),
Obx(() { AnimatedSwitcher(
// 移除连接失败和连接中的状态判断,直接根据是否完全连接来判断 duration: const Duration(milliseconds: 300),
// 使用响应式访问确保UI更新 transitionBuilder: (Widget child, Animation<double> animation) {
return controller.isFullyConnectedRx.value return FadeTransition(
? _buildConnectedDeviceInfo(isDarkMode) //已连接设备信息 opacity: animation,
: _buildDisconnectedInfo(isDarkMode); //未连接提示 child: SlideTransition(
}), position: Tween<Offset>(
begin: const Offset(0, 0.1),
// 连接按钮(仅在未连接时显示) end: Offset.zero,
).animate(animation),
child: child,
),
);
},
child: Container(
key: ValueKey('device_info_$isConnected'),
child: isConnected
? _buildConnectedDeviceInfo(isDarkMode)
: _buildDisconnectedInfo(isDarkMode),
),
),
// 连接按钮 - 使用 AnimatedSwitcher 实现按钮切换动画
SizedBox(height: 12.h), SizedBox(height: 12.h),
Obx(() { AnimatedSwitcher(
// 使用响应式访问确保UI更新 duration: const Duration(milliseconds: 300),
if (!controller.isFullyConnectedRx.value) { transitionBuilder: (Widget child, Animation<double> animation) {
return _buildConnectButton(); return FadeTransition(
} else { opacity: animation,
return _buildDeviceButton(isDarkMode); child: SlideTransition(
} position: Tween<Offset>(
}), begin: const Offset(0, 0.1),
end: Offset.zero,
).animate(animation),
child: child,
),
);
},
child: Container(
key: ValueKey('device_button_$isConnected'),
child: !isConnected
? _buildConnectButton()
: _buildDeviceButton(isDarkMode),
),
),
], ],
), ),
); );

2
lib/modules/login/controllers/login_controller.dart

@ -845,7 +845,7 @@ class LoginController extends GetxController {
"name": params["name"], "name": params["name"],
"avatar": params["avatar"], "avatar": params["avatar"],
"language": _languageCode, "language": _languageCode,
"channel": _userChannel.toString(), "channel": _userChannel,
"version": _appVersion, "version": _appVersion,
}).timeout( }).timeout(
const Duration(seconds: 30), // 30秒超时 const Duration(seconds: 30), // 30秒超时

Loading…
Cancel
Save