Flutter:如何从自定义Stateful Widget获取控制器值存入本地存储
解决方案
要实现获取CustomTextFormField的输入值并保存到本地存储,最合理的方式是让父组件(注册页)管理输入控制器,避免直接访问子组件内部状态,以下是具体步骤:
步骤1:修改CustomTextFormField,支持外部传入控制器
将组件内部的_controller改为由父组件传入,这样父组件可以直接持有并获取输入值:
class CustomTextFormField extends StatefulWidget { // 新增外部控制器参数 final TextEditingController controller; const CustomTextFormField( {super.key, required this.hint, required this.inputType, required this.regExp, required this.controller}); final String hint; final TextInputType inputType; final RegExp regExp; @override State<CustomTextFormField> createState() => _CustomTextFormFieldState(); } class _CustomTextFormFieldState extends State<CustomTextFormField> { // 不再自行创建控制器,直接使用父组件传入的实例 @override void dispose() { // 注意:控制器由父组件创建,因此这里不需要销毁,交给父组件处理 super.dispose(); } @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(8.0), child: TextFormField( decoration: InputDecoration( hintText: widget.hint, fillColor: Colors.white, border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), ), controller: widget.controller, keyboardType: widget.inputType, validator: (value) { if (value == null || value.isEmpty) { return "Field can not be empty"; } if (widget.regExp.hasMatch(value)) { return "Field has invalid value"; } return null; }), ); } }
步骤2:在注册页管理控制器并实现本地存储逻辑
在RegisterPage的状态类中创建对应字段的控制器,传递给子组件,并完成用户信息的本地存储:
import 'package:shared_preferences/shared_preferences.dart'; import 'dart:convert'; class _RegisterPageState extends State<RegisterPage> { final _formKey = GlobalKey<FormState>(); // 创建各输入字段的控制器 final _userNameController = TextEditingController(); final _phoneNumController = TextEditingController(); final _passwordController = TextEditingController(); @override void dispose() { // 销毁所有控制器,避免内存泄漏 _userNameController.dispose(); _phoneNumController.dispose(); _passwordController.dispose(); super.dispose(); } // 保存用户信息到本地存储 Future<void> _saveUserToLocal() async { final prefs = await SharedPreferences.getInstance(); final user = User( phoneNum: _phoneNumController.text.trim(), email: "", // 若需要邮箱字段,可添加对应输入框及控制器 userName: _userNameController.text.trim(), passWord: _passwordController.text.trim(), ); // 将User实例转为JSON字符串存入本地 await prefs.setString('user', jsonEncode(user.toJson())); } @override Widget build(BuildContext context) { return GestureDetector( onTap: () { FocusScopeNode currentFocus = FocusScope.of(context); if (!currentFocus.hasPrimaryFocus) { currentFocus.unfocus(); } }, child: Scaffold( appBar: AppBar( backgroundColor: Colors.orange[50], ), body: SingleChildScrollView( child: Form( key: _formKey, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ CustomTextFormField( hint: 'Username', inputType: TextInputType.name, regExp: RegExpControl.userNameRegExp, controller: _userNameController), CustomTextFormField( hint: 'Phone number', inputType: TextInputType.phone, regExp: RegExpControl.phoneNumRegExp, controller: _phoneNumController), // 修改PasswordChecking组件,让它接收外部控制器(逻辑同CustomTextFormField) PasswordChecking(controller: _passwordController), MaterialButton( color: Colors.amber, onPressed: () async { if (_formKey.currentState!.validate()) { await _saveUserToLocal(); Navigator.pushNamedAndRemoveUntil( context, NamedRoute.homePageName, (route) => false); } else { Dialogs.alert(context, "Err", 'ERRR'); } }, child: const Text( "Register", style: TextStyle(color: Colors.black87), ), ), TextButton( onPressed: () { Navigator.pushNamedAndRemoveUntil( context, NamedRoute.loginPageName, (route) => false); }, child: const Text("Have an account ? Login")) ], ), ), ), ), ); } }
步骤3:完善User类的JSON转换方法
补充toJson方法,实现User实例与JSON的双向转换(同时修正原代码中formJson的拼写错误):
class User { String phoneNum; String email; String userName; String passWord; User({ required this.phoneNum, required this.email, required this.userName, required this.passWord, }); // 修正拼写错误:formJson → fromJson User.fromJson(Map<String, dynamic> json) : phoneNum = json['phoneNum'], email = json['email'], userName = json['userName'], passWord = json['passWord']; // 新增转JSON方法 Map<String, dynamic> toJson() { return { 'phoneNum': phoneNum, 'email': email, 'userName': userName, 'passWord': passWord, }; } }
可选:修改PasswordChecking组件
参照CustomTextFormField的修改方式,让PasswordChecking支持外部传入控制器,确保能获取密码输入值。
内容的提问来源于stack exchange,提问作者Ken
相关产品推荐
相关产品推荐

