Search code examples
flutterkeyboardtextfieldstatefulflutter-showmodalbottomsheet

Flutter - TextField in StatefulBuilder in modalBottomSheet not working


I have a problem. In my code, I call showModalBottomSheet and inside of it, I have a feedback form. The user can select a reaction and then leave a comment to submit.

Therefore, I had to use a StatefulBuilder to use setState inside the modal. The TextField has a weird behavior though—when I click on it, the keyboard appears for an instant and then the modal is reset to the original state. If I remove the StatefulBuilder and I leave the GestureDetector as main Widget, everything works as expected (the keyboard appears, the modal moves to show it, and so on).

Is there any way to make the StatefulBuilder and the TextField coexist? Below there is a snippet of code, appropriately cut to focus on this problem.

TextEditingController feedbackTextFieldController = TextEditingController();

...

showModalBottomSheet<void>(
    context: context,
    isScrollControlled: true, // makes content maxHeight = full device height
    builder: (BuildContext context) {
      bool _isFeedbackLoading = false;

      return StatefulBuilder(
        builder: (context, setState) => GestureDetector(
          onTap: () {
            // the following is needed to dismiss the keyboard on tap outside of it
            FocusScopeNode currentFocus = FocusScope.of(context);

            if (!currentFocus.hasPrimaryFocus) {
              currentFocus.unfocus();
            }
          },
          child: AnimatedPadding(
            // to make the modal move when the keyboard is shown
            padding: MediaQuery.of(context).viewInsets,
            duration: const Duration(milliseconds: 100),
            curve: Curves.decelerate,
            child: Container(
              child: _isFeedbackLoading
                  ? Center(
                      child: CircularProgressIndicator(),
                    )
                  : TextField(
                      controller: feedbackTextFieldController,
                      textInputAction: TextInputAction.done,
                      textCapitalization: TextCapitalization.sentences,
                      maxLines: 2,
                      style: ...,
                      decoration: ...,
                    ),
            ),
          ),
        ),
      );
    },
  );

Thank you!


Solution

  • you can give try to following code

    showModalBottomSheet<void>(
        context: context,
        isScrollControlled: true, // makes content maxHeight = full device height
        builder: (BuildContext context) {
          bool _isFeedbackLoading = false;
    
          return StatefulBuilder(
            // it could also because of you may reaching the wrong context
            // builder: (context, setState) => GestureDetector(
            builder: (_, setState) => GestureDetector(
              // may be you are not able to tap
              behavior: HitTestBehavior.opaque,
              onTap: () {
                // the following is needed to dismiss the keyboard on tap outside of it
                FocusScopeNode currentFocus = FocusScope.of(context);
    
                if (!currentFocus.hasPrimaryFocus) {
                  currentFocus.unfocus();
                }
              },
              child: AnimatedPadding(
                // to make the modal move when the keyboard is shown
                padding: MediaQuery.of(context).viewInsets,
                duration: const Duration(milliseconds: 100),
                curve: Curves.decelerate,
                child: Container(
                  child: _isFeedbackLoading
                      ? Center(
                          child: CircularProgressIndicator(),
                        )
                      : TextField(
                          controller: feedbackTextFieldController,
                          textInputAction: TextInputAction.done,
                          textCapitalization: TextCapitalization.sentences,
                          maxLines: 2,
                          style: ...,
                          decoration: ...,
                        ),
                ),
              ),
            ),
          );
        },
      );
    

    or you can try to make it another StatefulWidget for this, like following

    showModalBottomSheet<void>(
        context: context,
        isScrollControlled: true, // makes content maxHeight = full device height
        builder: (BuildContext context) {
          return YourRefactoredStatefulWidget();
        }
    .....