'TextField is gaining focus after navigating to another screen

In my project I've wrapped the whole MaterialApp in a GestureDetector which is supposed to dismiss keyboard when user tapped the screen, using this piece of code

FocusScope.of(context).unfocus()

After testing multiple scenarios it wasn't working so I decided to do it the wrong way

FocusScope.of(context).requestFocus(FocusNode())

But now I'm experiencing another issue. Here is my code for a simple screen which is instantiated by MaterialApp's routes builder.

import 'package:flutter/material.dart';

class TestScreen extends StatefulWidget {
  @override
  _TestScreenState createState() => _TestScreenState();
}

class _TestScreenState extends State<TestScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          TextFormField(),
          FlatButton(
              onPressed: () => Navigator.push(context,
                  MaterialPageRoute(builder: (context) => TestScreen())),
              child: Text('Test'))
        ],
      ),
    );
  }
}

The steps to reproduce error is: 1-Start editing TextField. 2-Unfocus TextField by tapping somewhere on screen. 3-Tap on button to navigate to another screen. This is the result:

enter image description here

This behavior is not happening when I'm trying to unfocus TextField by pressing keyboard's done button. According to the source code when done button is pressed, TextField is calling clearComposing on TextEditingController. I even tried that but got no luck. How can I fix it? Does anyone else have better solution to handle dismissing keyboard in Flutter?

Also here is my flutter doctor result:

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.17.5, on Mac OS X 10.15.5 19F101, locale en-US)
 
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[✓] Xcode - develop for iOS and macOS (Xcode 11.6)
[✓] Android Studio (version 4.0)
[✓] VS Code (version 1.47.3)
[✓] Connected device (2 available)

• No issues found!


Solution 1:[1]

After searching a lot on GitHub issues related to focus management, It seems that no one knows what is the right way to do this. Finally this line of code solved my issue:

WidgetsBinding.instance.focusManager.primaryFocus?.unfocus();

I'm not aware of side effects of it but It's working for now.

Solution 2:[2]

You are facing two problems here:

  1. The expected behaviour in flutter is when pushing to a new route the focus of the previous route persists, which implies that when you pop back the TextField is still on focus. Refer to this flutter github discussion about the topic.

  2. You have two GestureDetector's which are tringgered by an onTap pointer gesture. Your wrapper which you use to dismiss the focus, and the FlatButton to navigate to the other route. When you tap the button the underlying GestureRecognizer gives the hanlding control of this event to the button, and the wrapper GestureDetector opTap() is not called (which implies unfocus is not called).

Solution 3:[3]

Set a focusNode to the text field and, after push the new route, focus next node and unfocus current, like:

// push your new route here

myNode.nextFocus();
myNode.unfocus();
// myNode needs to be the last text field

When you press back, from the new route, the focus will not reappear automatically anymore.

Worked for me.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 pcba-dev
Solution 3 Márcio Valim