diff --git a/lib/modules/translation/views/widgets/face_to_face_layout.dart b/lib/modules/translation/views/widgets/face_to_face_layout.dart index 562a543b9..efc6140a3 100644 --- a/lib/modules/translation/views/widgets/face_to_face_layout.dart +++ b/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 createState() => _FaceToFaceLayoutState(); +} + +class _FaceToFaceLayoutState extends State { + 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,