I have a text field where the user enters text. But I ran into a problem when I enter text and press the Done button - the text disappears from the text field as if it never existed. But when the field is active and I enter characters, everything is visible. Why does the text disappear from the text field after clicking the Done button?
class CommentWidget extends StatelessWidget {
final Function(String) onChanged;
final String? textForm;
final bool isHelpPage;
CommentWidget({Key? key, required this.onChanged, required this.textForm, required this.isHelpPage})
: super(key: key);
final TextEditingController controller = TextEditingController();
String value = '';
@override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
controller.text = textForm ?? '';
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
isHelpPage
? const SizedBox()
: const ResizedText(
'Comments',
textStyle: constants.Styles.smallTextStyleWhite,
),
SizedBox(
height: UiSize.getHeight(15, size),
),
Container(
height: UiSize.getHeight(isHelpPage ? 290 : 150, size),
width: UiSize.getWidth(360, size),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: constants.Colors.purpleMain,
width: 0.5,
),
),
child: Padding(
padding: EdgeInsets.only(
top: UiSize.getHeight(16, size),
left: UiSize.getWidth(18, size),
right: UiSize.getWidth(18, size),
bottom: UiSize.getHeight(16, size),
),
child: TextField(
maxLines: isHelpPage ? 10 :4,
maxLength: isHelpPage ? 1500 : 450,
controller: controller,
style: constants.Styles.smallerBookTextStyleWhiteOpacity,
textInputAction: TextInputAction.done,
onChanged: (text) {
onChanged(text);
value = text;
},
decoration: InputDecoration(
border: InputBorder.none,
helperStyle: constants.Styles.smallerBookTextStyleWhiteOpacity,
hintStyle: constants.Styles.smallerBookTextStyleWhiteOpacity,
hintText: 'Here you can describe the problem in more detail',
),
),
),
),
],
);
}
}
body
class ReportBody extends StatelessWidget {
final bool isHelpPage;
ReportBody({Key? key, required this.isHelpPage}) : super(key: key);
final TextEditingController controller = TextEditingController();
@override
Widget build(BuildContext context) {
String? comment;
final Size size = MediaQuery.of(context).size;
return Container(
height: size.height,
width: size.width,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/background/main_background.png'),
fit: BoxFit.cover,
),
),
child: _child(size, comment),
);
}
Widget _child(Size size, String? comment) =>
BlocBuilder<ReportCubit, ReportState>(
builder: (context, state) {
final ReportCubit cubit = BlocProvider.of<ReportCubit>(context);
if (state is ReportInitial) {
return _part(cubit, context, size, state, comment);
}
return Container();
},
);
Widget _part(
ReportCubit cubit,
BuildContext context,
Size size,
ReportInitial state,
String? comment,
) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 135,
),
Padding(
padding: const EdgeInsets.only(left: 30, right: 30),
child: BackstepWidget(
text: 'Report a problem',
onBackPressed: () => Routemaster.of(context).pop(),
),
),
state.isPhotoEnabled && state.reports[0]
? Expanded(
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: _reportBody(cubit, context, size, state, comment),
),
)
: Expanded(child: _reportBody(cubit, context, size, state, comment))
],
);
}
Widget _reportBody(
ReportCubit cubit,
BuildContext context,
Size size,
ReportInitial state,
String? comment,
) {
return isHelpPage
? SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: isHelpPage && state.isPhotoEnabled
? size.height * 0.98
: size.height * .77,
),
child: _reportWidget(cubit, context, size, state, comment),
),
)
: _reportWidget(cubit, context, size, state, comment);
}
Widget _reportWidget(
ReportCubit cubit,
BuildContext context,
Size size,
ReportInitial state,
String? comment,
) {
return Column(
children: [
if (state.reports[0] || isHelpPage)
Padding(
padding: EdgeInsets.only(
top: isHelpPage ? 0 : UiSize.getHeight(48, size),
bottom: UiSize.getHeight(30, size),
right: UiSize.getWidth(28, size),
left: UiSize.getWidth(28, size),
),
child: CommentWidget(
textForm: comment,
onChanged: (text) {
state.comment = text;
comment = text;
print(comment);
},
isHelpPage: isHelpPage,
),
),
CodePudding user response:
My guess is that you are rebuilding the textfield in the parent widget by maybe calling setState(...).
controller.text = textForm ?? '';
then wipes your text because you are resetting the text every time you are building the widget.
Solution: Make the widget a StatefulWidget and let it cache the value of the TextField.
This could look something like this
class TextfieldWithCache extends StatefulWidget {
const TextfieldWithCache(this.initialValue, this.onUpdate);
final String initialValue;
final Function(String) onUpdate;
@override
State<TextfieldWithCache> createState() => TextfieldWithCacheState();
}
class TextfieldWithCacheState extends State<TextfieldWithCache> {
// if not used in this widget, the value can be deleted as well
String _cachedValue;
Widget build(BuildContext context) {
return TextFormField(
initialValue: widget.initialValue,
onChanged: (String value) {
widget.onUpdate(value);
_cachedValue = value;
},
);
}
}
Note: If you don't use the cached value in the TextfieldWithCache then you can remove it as well.
The core lies in using a StatefulWidget and getting rid of all helper methods involved in widget creation.
CodePudding user response:
Try changing the ReportBody to Statefull Widget
and declare the text editing controller as and intialize it in the initState(),
late final TextEditingController controller;
@override
void initState() {
controller = TextEditingController();
super.initState();
}
Then pass this controller to CommentWidget
as a named paramater and use this contoller to TextFormField.
Hope it works.