skip to Main Content

I am trying to close the keyboard input from a textfield and a showModalBottomSheet, all in one action, just tapping the back button once (android, not tested in ios). The issue is my textfield needs to have the ‘autofocus: true’ for my needs, but when trying to close the keyboard and the showModalBottomSheet, only the keyboard will close and the user has to tap the backbutton again to close the showModalBottomSheet, which is so akward.

Tapping outside the showModalBottomSheet will do the trick, but I would also like to make it possible with the phone’s back button.

My code:

If more code is needed, please let me know.

        FloatingActionButton(
          heroTag: null,
          tooltip: 'Add a new task',
          onPressed: () async {
            showModalBottomSheet(
              shape: const RoundedRectangleBorder(),
              context: context,
              isDismissible: true,
              builder: (BuildContext context) {
                return SingleChildScrollView(
                  padding: EdgeInsets.only(
                    bottom: MediaQuery.of(context).viewInsets.bottom,
                  ),
                  child: Row(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      Expanded(
                        child: Padding(
                          padding: const EdgeInsets.all(12),
                          child: TextField(                           
                            controller: _newTaskTextController,
                            autofocus: true,
                            onSubmitted: (_) {
                              creatingNewTask();
                            },
                          ),
                        ),
                      ),
                      IconButton(
                        onPressed: () {
                          creatingNewTask();
                        },
                        icon: const Icon(Icons.done),
                      ),
                    ],
                  ),
                );
              },
            );
          },
          child: const Icon(Icons.add),
        ),

I’ve tried using WillPopScope wrapping the Scaffold, the FloatingActionButton, even the TextField, but willPop NEVER triggers on the first back button tap, since is closing the keyboard, it will only trigger on the second tap (when the keyboard is closed).

I expect to close the showModalBottomSheet dialog and the focused keyboard just tapping the backbutton once.

2

Answers


  1.  Wrap the Material App in Gesture Detector and write this in onTap method.
    
     final FocusScopeNode currentFocus = FocusScope.of(context);
                if (!currentFocus.hasPrimaryFocus) {
                  currentFocus.requestFocus(FocusNode());
                }
    
    It's mean you tap outside the textfield then keyboard closed.
    
    
    Login or Signup to reply.
  2. To achieve the desired behavior of closing both the keyboard and the showModalBottomSheet with a single tap on the back button, you can use the WillPopScope widget in Flutter. This widget allows you to intercept the back button press and perform custom actions.

    Here’s an example of how you can use WillPopScope to achieve the desired behavior:

    import 'package:flutter/material.dart';
    
    class MyWidget extends StatefulWidget {
      @override
      _MyWidgetState createState() => _MyWidgetState();
    }
    
    class _MyWidgetState extends State<MyWidget> {
      TextEditingController _textEditingController = TextEditingController();
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('My App'),
          ),
          body: WillPopScope(
            onWillPop: () async {
              // Close the keyboard
              FocusScope.of(context).unfocus();
    
              // Check if the bottom sheet is open
              if (Navigator.of(context).userGestureInProgress) {
                // Close the bottom sheet
                Navigator.of(context).pop();
                return false; // Prevent default back button behavior
              }
    
              return true; // Allow default back button behavior
            },
            child: Column(
              children: [
                TextField(
                  autofocus: true,
                  controller: _textEditingController,
                ),
                ElevatedButton(
                  onPressed: () {
                    showModalBottomSheet(
                      context: context,
                      builder: (context) => Container(
                        height: 200,
                        child: Center(
                          child: Text('Modal Bottom Sheet'),
                        ),
                      ),
                    );
                  },
                  child: Text('Show Bottom Sheet'),
                ),
              ],
            ),
          ),
        );
      }
    }
    

    In this example, the WillPopScope widget wraps the main content of your screen. The onWillPop callback is triggered when the back button is pressed. Inside the callback, you first close the keyboard by calling FocusScope.of(context).unfocus(). Then, you check if the bottom sheet is open by using Navigator.of(context).userGestureInProgress. If the bottom sheet is open, you close it by calling Navigator.of(context).pop() and return false to prevent the default back button behavior. If the bottom sheet is not open, you allow the default back button behavior by returning true.

    This way, when the back button is pressed, both the keyboard and the bottom sheet will be closed simultaneously, providing a smoother user experience.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search