Flutter开发中Cubit结果为何在第二个TextField输入前显示
问题原因
- 当前使用StatelessWidget,build方法内定义的
str变量是局部临时变量,点击提交修改str不会触发UI重建,无法控制校验组件的显隐 - 初始化阶段
str和mycontroller.text都为空值,if (str == mycontroller.text)条件直接成立,导致校验结果提前渲染 - Cubit使用逻辑错误:没有通过emit发送状态,而是直接调用方法返回字符串,没有用到Bloc状态管理的能力,也无法通过状态控制结果显隐
- TextEditingController在StatelessWidget中使用无法正确释放,会造成内存泄漏
修复方案
1. 修正SentenceCubit逻辑
将校验逻辑改为 emit 对应状态,而不是直接返回字符串:
import 'package:bloc/bloc.dart'; import 'package:meta/meta.dart'; part 'sentence_state.dart'; class SentenceCubit extends Cubit<SentenceState> { SentenceCubit() : super(SentenceInitial()); void checkForError(String secondInput, String originalInput) { if (secondInput.trim() == originalInput.trim()) { emit(Success(okay: "OKAY")); } else { emit(Failed(notOkay: "Not Okay")); } } // 重置状态的方法,用户输入修改时清空结果 void resetState() { emit(SentenceInitial()); } }
2. 将页面改为StatefulWidget,调整UI逻辑
import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:rafia_unscramble_demo/cubit/sentence_cubit.dart'; class ScrambledUnscrambled extends StatefulWidget { final String? userInputFromFirstTextField; const ScrambledUnscrambled({ super.key, required this.userInputFromFirstTextField, }); @override State<ScrambledUnscrambled> createState() => _ScrambledUnscrambledState(); } class _ScrambledUnscrambledState extends State<ScrambledUnscrambled> { late final TextEditingController mycontroller; // 缓存打乱后的字符串,避免每次build重新打乱 late final String shuffledSentence; @override void initState() { super.initState(); mycontroller = TextEditingController(); // 初始化时就生成唯一的打乱字符串 final inputs = widget.userInputFromFirstTextField!.split(" "); inputs.shuffle(); shuffledSentence = inputs.join(" "); } @override void dispose() { mycontroller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return BlocProvider<SentenceCubit>( create: (context) => SentenceCubit(), child: Scaffold( appBar: AppBar( title: const Text('Unscramble'), ), body: Column( children: [ Card( margin: const EdgeInsets.only(top: 50), child: Container( alignment: Alignment.center, width: double.infinity, height: 100, color: Colors.blueAccent, padding: const EdgeInsets.all(15), child: Text( shuffledSentence, style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), ), const SizedBox(height: 20), Container( padding: const EdgeInsets.all(20), alignment: Alignment.center, child: TextField( controller: mycontroller, onChanged: (String text) { // 用户修改输入时清空之前的校验结果 context.read<SentenceCubit>().resetState(); }, decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), ), hintText: 'Please, enter a grammatically correct sentence.', labelText: 'Second Input', labelStyle: TextStyle( fontSize: 24, color: Colors.blue[900], ), ), ), ), ElevatedButton( onPressed: () { // 点击提交触发校验 context.read<SentenceCubit>().checkForError( mycontroller.text, widget.userInputFromFirstTextField!, ); }, child: const Text("Submit"), ), BlocBuilder<SentenceCubit, SentenceState>( builder: (context, state) { // 根据状态显示对应内容,初始状态不显示 if (state is Success) { return Container( color: Colors.green, padding: const EdgeInsets.all(20), width: double.infinity, height: 100, child: Center( child: Text( state.okay, style: const TextStyle(color: Colors.white, fontSize: 24), ), ), ); } else if (state is Failed) { return Container( color: Colors.redAccent, padding: const EdgeInsets.all(20), width: double.infinity, height: 100, child: Center( child: Text( state.notOkay, style: const TextStyle(color: Colors.white, fontSize: 24), ), ), ); } // 初始状态返回空组件,不显示结果 return const SizedBox.shrink(); }, ), ], ), ), ); } }
修复后效果
- 页面初始化时不会显示校验结果
- 用户输入修改时会自动清空之前的校验提示
- 只有点击提交按钮后才会触发校验,根据匹配结果显示对应提示
- 打乱后的字符串不会因为UI重建反复变更,符合功能预期
内容的提问来源于stack exchange,提问作者RafiaChy
相关产品推荐
相关产品推荐

