Browse Source

refactor(translation): 将面对面布局组件改为有状态组件并添加滚动功能

将StatelessWidget改为StatefulWidget以管理滚动控制器
添加自动滚动到底部功能,提升长文本浏览体验
优化布局内边距,防止底部内容被遮挡
weicu
lxm 11 months ago
parent
commit
fdd7c098a5
  1. 130
      lib/modules/translation/views/widgets/face_to_face_layout.dart

130
lib/modules/translation/views/widgets/face_to_face_layout.dart

@ -7,7 +7,7 @@ import '../../../../core/theme/app_colors.dart';
import '../dialogs/language_selection_dialog.dart';
/// 面对面翻译布局组件
class FaceToFaceLayout extends StatelessWidget {
class FaceToFaceLayout extends StatefulWidget {
final bool isDarkMode;
final TranslationController controller;
@ -17,13 +17,60 @@ class FaceToFaceLayout extends StatelessWidget {
required this.controller,
}) : super(key: key);
@override
State<FaceToFaceLayout> createState() => _FaceToFaceLayoutState();
}
class _FaceToFaceLayoutState extends State<FaceToFaceLayout> {
final ScrollController _topScrollController = ScrollController();
final ScrollController _bottomScrollController = ScrollController();
@override
void dispose() {
_topScrollController.dispose();
_bottomScrollController.dispose();
super.dispose();
}
void _scrollToBottom({bool animate = false}) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (_topScrollController.hasClients) {
final m = _topScrollController.position.maxScrollExtent;
if (animate) {
_topScrollController.animateTo(
m,
duration: const Duration(milliseconds: 200),
curve: Curves.easeOut,
);
} else {
_topScrollController.jumpTo(m);
}
}
if (_bottomScrollController.hasClients) {
final m2 = _bottomScrollController.position.maxScrollExtent;
if (animate) {
_bottomScrollController.animateTo(
m2,
duration: const Duration(milliseconds: 200),
curve: Curves.easeOut,
);
} else {
_bottomScrollController.jumpTo(m2);
}
}
});
}
@override
Widget build(BuildContext context) {
final isDarkMode = widget.isDarkMode;
final controller = widget.controller;
return Obx(() {
// 获取最新的翻译记录
final latestItem = controller.translationHistory.isNotEmpty
? controller.translationHistory.last
: null;
_scrollToBottom(animate: false);
return Column(
children: [
@ -33,7 +80,7 @@ class FaceToFaceLayout extends StatelessWidget {
angle: 3.14159, // 180度 = π弧度
child: Container(
width: double.infinity,
padding: EdgeInsets.all(24.w),
padding: EdgeInsets.fromLTRB(24.w, 24.w, 24.w, 24.w + 96.h),
decoration: BoxDecoration(
color: isDarkMode
? AppColors.cardBackground.withValues(alpha: 0.5)
@ -45,24 +92,22 @@ class FaceToFaceLayout extends StatelessWidget {
),
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 上半部的文本
Text(
latestItem?.targetLanguageCode ==
controller.targetLanguageCode.value
? latestItem?.translatedText ?? '' //如果为null则显示空字符
: latestItem?.sourceText ?? '',
style: TextStyle(
fontSize: 20.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white : Colors.black87,
height: 1.4,
),
textAlign: TextAlign.center,
child: SingleChildScrollView(
controller: _topScrollController,
physics: const BouncingScrollPhysics(),
child: Text(
latestItem?.targetLanguageCode ==
controller.targetLanguageCode.value
? latestItem?.translatedText ?? ''
: latestItem?.sourceText ?? '',
style: TextStyle(
fontSize: 20.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white : Colors.black87,
height: 1.4,
),
],
textAlign: TextAlign.center,
),
),
),
),
@ -75,33 +120,31 @@ class FaceToFaceLayout extends StatelessWidget {
Expanded(
child: Container(
width: double.infinity,
padding: EdgeInsets.all(24.w),
padding: EdgeInsets.fromLTRB(24.w, 24.w, 24.w, 24.w + 96.h),
decoration: BoxDecoration(
color: isDarkMode
? AppColors.cardBackground.withValues(alpha: 0.5)
: Colors.green[50]?.withValues(alpha: 0.3),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 下半部的文本
Text(
latestItem?.sourceLanguageCode ==
controller.sourceLanguageCode.value
? latestItem?.sourceText ??
(controller.faceToFaceRecognitionText.value.isEmpty
? ''
: controller.faceToFaceRecognitionText.value)
: latestItem?.translatedText ?? '',
style: TextStyle(
fontSize: 20.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white : Colors.black87,
height: 1.4,
),
textAlign: TextAlign.center,
child: SingleChildScrollView(
controller: _bottomScrollController,
physics: const BouncingScrollPhysics(),
child: Text(
latestItem?.sourceLanguageCode ==
controller.sourceLanguageCode.value
? latestItem?.sourceText ??
(controller.faceToFaceRecognitionText.value.isEmpty
? ''
: controller.faceToFaceRecognitionText.value)
: latestItem?.translatedText ?? '',
style: TextStyle(
fontSize: 20.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white : Colors.black87,
height: 1.4,
),
],
textAlign: TextAlign.center,
),
),
),
),
@ -146,7 +189,7 @@ class FaceToFaceLayout extends StatelessWidget {
borderRadius: BorderRadius.circular(16.r),
),
child: Text(
'${controller.sourceLanguage.value.split(' ')[0]}'.tr,
'${widget.controller.sourceLanguage.value.split(' ')[0]}'.tr,
style: TextStyle(
fontSize: 15.sp,
fontWeight: FontWeight.w600,
@ -161,7 +204,7 @@ class FaceToFaceLayout extends StatelessWidget {
// 语言互换按钮
GestureDetector(
onTap: controller.swapLanguages,
onTap: widget.controller.swapLanguages,
child: Container(
margin: EdgeInsets.symmetric(horizontal: 8.w),
padding: EdgeInsets.all(4.r),
@ -194,7 +237,8 @@ class FaceToFaceLayout extends StatelessWidget {
child: Transform.rotate(
angle: 3.14159, // 旋转180度
child: Text(
'${controller.targetLanguage.value.split(' ')[0]}'.tr,
'${widget.controller.targetLanguage.value.split(' ')[0]}'
.tr,
style: TextStyle(
fontSize: 15.sp,
fontWeight: FontWeight.w600,

Loading…
Cancel
Save