Flutter Web屏幕尺寸变化时输入框状态重置问题求解
问题修复方案
核心问题原因
你当前的实现中,DesktopView和MobileView是两个独立的StatefulWidget,各自维护自己的TextEditingController和状态。当屏幕尺寸切换时,Flutter会销毁旧的视图组件,创建新的视图实例,新实例的控制器是全新的空对象,导致输入内容被清空。
修复步骤
1. 将状态提升到父组件
把共享的状态和控制器移到最上层的LoginDetails组件,让它变成StatefulWidget,这样所有视图共享同一套状态:
class LoginDetails extends StatefulWidget { const LoginDetails({Key? key}) : super(key: key); @override State<LoginDetails> createState() => _LoginDetailsState(); } class _LoginDetailsState extends State<LoginDetails> { // 共享的控制器和状态 final emailController = TextEditingController(); final passwordController = TextEditingController(); int userId = 0; bool _isAuthorized = false; bool _hasLicense = false; void loginUser() { // 保留你的登录逻辑 } @override void dispose() { // 记得销毁控制器,避免内存泄漏 emailController.dispose(); passwordController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ const Color(0xFFAA00FF), const Color.fromARGB(255, 135, 90, 86), const Color.fromARGB(255, 229, 255, 0), ], ), ), child: ResponsiveLayout( // 将共享状态传递给各个视图 largeScreen: DesktopView( emailController: emailController, passwordController: passwordController, loginUser: loginUser, ), mediumScreen: TabletView( emailController: emailController, passwordController: passwordController, loginUser: loginUser, ), smallScreen: MobileView( emailController: emailController, passwordController: passwordController, loginUser: loginUser, ), ), ); } }
2. 修改子视图为无状态组件
让DesktopView和MobileView变成StatelessWidget,只负责渲染布局,不再维护自己的状态:
class DesktopView extends StatelessWidget { final TextEditingController emailController; final TextEditingController passwordController; final VoidCallback loginUser; const DesktopView({ Key? key, required this.emailController, required this.passwordController, required this.loginUser, }) : super(key: key); @override Widget build(BuildContext context) { return Container( child: Column( children: [ const SizedBox(height: 10), Text( 'Авторизация', style: TextStyle( color: Colors.white, fontSize: 80, fontWeight: FontWeight.bold, fontFamily: 'Jura', ), ), Expanded( child: Center( child: Wrap( children: [ LoginCard( emailController: emailController, passwordController: passwordController, loginUser: loginUser, ), ], ), ), ), ], ), ); } } class MobileView extends StatelessWidget { final TextEditingController emailController; final TextEditingController passwordController; final VoidCallback loginUser; const MobileView({ Key? key, required this.emailController, required this.passwordController, required this.loginUser, }) : super(key: key); @override Widget build(BuildContext context) { return SingleChildScrollView( child: Container( padding: const EdgeInsets.symmetric(horizontal: 20), child: Column( children: [ const SizedBox(height: 20), Text( 'Авторизация', style: TextStyle( color: Colors.white, fontSize: 48, fontWeight: FontWeight.bold, fontFamily: 'Jura', ), ), Center( child: Wrap( children: [ LoginCard( emailController: emailController, passwordController: passwordController, loginUser: loginUser, ), ], ), ), ], ), ), ); } }
3. 补充TabletView的修改
按照同样的逻辑修改TabletView,让它也接收父组件传递的控制器和回调,确保所有视图共享同一状态。
为什么这样能解决问题
状态被提升到父组件后,无论屏幕尺寸如何切换,LoginDetails的State始终存在,控制器和输入内容不会被销毁。子视图只是根据布局需求渲染不同的UI结构,使用的都是父组件传递过来的同一个控制器,所以输入内容会被保留。
内容的提问来源于stack exchange,提问作者Hyper
相关产品推荐
相关产品推荐

