Como posso descartar o teclado na tela?


139

Estou coletando a entrada do usuário com um TextFormFielde quando o usuário pressiona a FloatingActionButtonindicando que terminou, desejo descartar o teclado na tela.

Como faço o teclado desaparecer automaticamente?

import 'package:flutter/material.dart';

class MyHomePage extends StatefulWidget {
  MyHomePageState createState() => new MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  TextEditingController _controller = new TextEditingController();

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(),
      floatingActionButton: new FloatingActionButton(
        child: new Icon(Icons.send),
        onPressed: () {
          setState(() {
            // send message
            // dismiss on screen keyboard here
            _controller.clear();
          });
        },
      ),
      body: new Container(
        alignment: FractionalOffset.center,
        padding: new EdgeInsets.all(20.0),
        child: new TextFormField(
          controller: _controller,
          decoration: new InputDecoration(labelText: 'Example Text'),
        ),
      ),
    );
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
    );
  }
}

void main() {
  runApp(new MyApp());
}

Collin, A segunda resposta de @Pascal deve ser a resposta atualizada e corrigida.
Jack

Respostas:


233

A partir do Flutter v1.7.8 + hotfix.2, o caminho a seguir é:

FocusScope.of(context).unfocus()

Comente sobre RP sobre isso:

Agora que # 31909 (be75fb3) pousou, você deve usar em FocusScope.of(context).unfocus()vez de FocusScope.of(context).requestFocus(FocusNode()), uma vez que FocusNodes são ChangeNotifiers, e devem ser descartados corretamente.

-> NÃO use ̶r̶e̶q̶u̶e̶s̶t̶F̶o̶c̶u̶s̶(̶F̶o̶c̶u̶s̶N̶o̶d̶e̶(̶)̶mais.

 F̶o̶c̶u̶s̶S̶c̶o̶p̶e̶.̶o̶f̶(̶c̶o̶n̶t̶e̶x̶t̶)̶.̶r̶e̶q̶u̶e̶s̶t̶F̶o̶c̶u̶s̶(̶F̶o̶c̶u̶s̶N̶o̶d̶e̶(̶)̶)̶;̶

1
Trabalhou para mim no hotfix v1.7.8 + hotfix.4
Rajesh Jr.

2
funcione para mim, esta resposta deve ser mascarada como a correta
user3087360

@kine você pode explicar? De acordo com a documentação, esta é a maneira de fazer (consulte api.flutter.dev/flutter/widgets/FocusNode/unfocus.html )
Pascal

@Pascal Sim, li a documentação e esta teria sido a minha solução preferida, mas no meu aplicativo nem sempre funciona (uma forma bastante complexa com vários se TextFieldoutros widgets de edição). Não sei porquê, mas às vezes unfocusnão surte efeito. Substituí-lo pela solução aceita (sem outras alterações) corrige o problema. Talvez esteja relacionado ao local de onde unfocusé chamado. Eu preciso chamá-lo, por exemplo, de CheckBoxListTile.onChangedpara dispensar o teclado quando o usuário interage com um widget de caixa de seleção e de outros locais semelhantes. Não me lembro do local exato do problema.
vacas

@kine Obrigado pela explicação. Fornecer um exemplo para a equipe do Flutter seria incrível ;-)
Pascal

210

Nota: esta resposta está desatualizada. Veja a resposta para versões mais recentes do Flutter .

Você pode dispensar o teclado retirando o foco do TextFormFielde dando-o a um não utilizado FocusNode:

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

Onde você implementaria este código? No TextFormField; talvez depois onChanged:ou na ação de seu botão personalizado?
Charles Jr

@CharlesJr Eu faço isso na ação do meu botão.
Duncan Jones

você pode usar meu pacote se quiser :) pub.dartlang.org/packages/keyboard_actions
diegoveloper

17
Isso é antes do Flutter v1.7.8 - consulte a resposta stackoverflow.com/a/56946311/8696915 que dáFocusScope.of(context).unfocus()
Richard Johnson

1
Não faça isso se você tiver acesso a .unfocus (), pois isso causará um vazamento de memória. Esse novo FocusNode () nunca será limpo. Ver comentário sobre .unfocus ()
Michael Peterson

70

A solução com FocusScope não funciona para mim. Eu encontrei outro:

import 'package:flutter/services.dart';

SystemChannels.textInput.invokeMethod('TextInput.hide');

Isso resolveu meu problema.


Chamar isso não esconde o teclado para mim. Deve funcionar em Android e iOS?
Jardo

Funcionou para mim no iOS (12.1, iPhone 5s) e Android (Pixel 3)
Jannie Theunissen

Onde você coloca isso? Eu tentei apenas adicioná-lo como o primeiro pedaço de código no aplicativo e não fez nada.
Justin808

O que você quer dizer com "o primeiro pedaço de código"? Insira-o no buildmétodo, por exemplo.
Andrey Turkovsky

1
existe um equivalente para isso para o teclado numérico?
Daniel Maksimovich

20

Para Flutter 1.17.3 (canal estável em junho de 2020), use

FocusManager.instance.primaryFocus.unfocus();


12

Nenhuma das soluções acima não funciona para mim.

Flutter sugere isso - Coloque seu widget dentro do novo GestureDetector () no qual o toque ocultará o teclado e, no toque, use FocusScope.of (contexto) .requestFocus (new FocusNode ())

class Home extends StatelessWidget {
@override
  Widget build(BuildContext context) {
    var widget = new MaterialApp(
        home: new Scaffold(
            body: new Container(
                height:500.0,
                child: new GestureDetector(
                    onTap: () {
                        FocusScope.of(context).requestFocus(new FocusNode());
                    },
                    child: new Container(
                        color: Colors.white,
                        child:  new Column(
                            mainAxisAlignment:  MainAxisAlignment.center,
                            crossAxisAlignment: CrossAxisAlignment.center,

                            children: [
                                new TextField( ),
                                new Text("Test"),                                
                            ],
                        )
                    )
                )
            )
        ),
    );

    return widget;
}}

12

O código a seguir me ajudou a esconder o teclado

   void initState() {
   SystemChannels.textInput.invokeMethod('TextInput.hide');
   super.initState();
   }

8
GestureDetector(
          onTap: () {
            FocusScope.of(context).unfocus();
          },
          child:Container(
    alignment: FractionalOffset.center,
    padding: new EdgeInsets.all(20.0),
    child: new TextFormField(
      controller: _controller,
      decoration: new InputDecoration(labelText: 'Example Text'),
    ),
  ), })

tente este gesto de toque


Obrigado ... peguei esta solução
Ajay Kumar

6

Como no Flutter tudo é um widget, decidi envolver o SystemChannels.textInput.invokeMethod('TextInput.hide');e a FocusScope.of(context).requestFocus(FocusNode());abordagem em um pequeno módulo de utilitário com um widget e um mixin nele.

Com o widget, você pode envolver qualquer widget (muito conveniente ao usar um bom suporte IDE) com o KeyboardHiderwidget:

class SimpleWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return KeyboardHider(
      /* Here comes a widget tree that eventually opens the keyboard,
       * but the widget that opened the keyboard doesn't necessarily
       * takes care of hiding it, so we wrap everything in a
       * KeyboardHider widget */
      child: Container(),
    );
  }
}

Com o mixin, você pode ativar a ocultação do teclado de qualquer estado ou widget em qualquer interação:

class SimpleWidget extends StatefulWidget {
  @override
  _SimpleWidgetState createState() => _SimpleWidgetState();
}

class _SimpleWidgetState extends State<SimpleWidget> with KeyboardHiderMixin {
  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      onPressed: () {
        // Hide the keyboard:
        hideKeyboard();
        // Do other stuff, for example:
        // Update the state, make an HTTP request, ...
      },
    );
  }
}

Basta criar um keyboard_hider.dartarquivo e o widget e o mixin estarão prontos para uso:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

/// Mixin that enables hiding the keyboard easily upon any interaction or logic
/// from any class.
abstract class KeyboardHiderMixin {
  void hideKeyboard({
    BuildContext context,
    bool hideTextInput = true,
    bool requestFocusNode = true,
  }) {
    if (hideTextInput) {
      SystemChannels.textInput.invokeMethod('TextInput.hide');
    }
    if (context != null && requestFocusNode) {
      FocusScope.of(context).requestFocus(FocusNode());
    }
  }
}

/// A widget that can be used to hide the text input that are opened by text
/// fields automatically on tap.
///
/// Delegates to [KeyboardHiderMixin] for hiding the keyboard on tap.
class KeyboardHider extends StatelessWidget with KeyboardHiderMixin {
  final Widget child;

  /// Decide whether to use
  /// `SystemChannels.textInput.invokeMethod('TextInput.hide');`
  /// to hide the keyboard
  final bool hideTextInput;
  final bool requestFocusNode;

  /// One of hideTextInput or requestFocusNode must be true, otherwise using the
  /// widget is pointless as it will not even try to hide the keyboard.
  const KeyboardHider({
    Key key,
    @required this.child,
    this.hideTextInput = true,
    this.requestFocusNode = true,
  })  : assert(child != null),
        assert(hideTextInput || requestFocusNode),
        super(key: key);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      behavior: HitTestBehavior.opaque,
      onTap: () {
        hideKeyboard(
          context: context,
          hideTextInput: hideTextInput,
          requestFocusNode: requestFocusNode,
        );
      },
      child: child,
    );
  }
}

4

Você pode usar o unfocus()método da FocusNodeclasse.

import 'package:flutter/material.dart';

class MyHomePage extends StatefulWidget {
  MyHomePageState createState() => new MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  TextEditingController _controller = new TextEditingController();
  FocusNode _focusNode = new FocusNode(); //1 - declare and initialize variable

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(),
      floatingActionButton: new FloatingActionButton(
        child: new Icon(Icons.send),
        onPressed: () {
            _focusNode.unfocus(); //3 - call this method here
        },
      ),
      body: new Container(
        alignment: FractionalOffset.center,
        padding: new EdgeInsets.all(20.0),
        child: new TextFormField(
          controller: _controller,
          focusNode: _focusNode, //2 - assign it to your TextFormField
          decoration: new InputDecoration(labelText: 'Example Text'),
        ),
      ),
    );
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
    );
  }
}

void main() {
  runApp(new MyApp());
}

1
Oi! Seria melhor se você pudesse editar sua resposta para adicionar um pouco mais de contexto a ela.
grooveplex

1
A melhor solução com a menor quantidade de codificação
Val

Sim, ele remove o foco se tocar em um widget específico. Não consigo adicioná-lo a todos os widgets do meu aplicativo.
Dpedrinha

Tocar em um widget é apenas uma maneira de chamar o unfocusmétodo. Se você não deseja enviar spam para o seu aplicativo, pode usar uma maneira diferente, como o TextFormFieldevento de alteração ou um padrão reativo, que depende da arquitetura do seu aplicativo.
Evandro Ap. S.

4

Parece abordagens diferentes para versões diferentes. Estou usando o Flutter v1.17.1 e o que está abaixo funciona para mim.

onTap: () {
    FocusScopeNode currentFocus = FocusScope.of(context);
    if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
       currentFocus.focusedChild.unfocus();
    }
}

1
_dismissKeyboard(BuildContext context) {
   FocusScope.of(context).requestFocus(new FocusNode());
}

@override
Widget build(BuildContext context) {

return new GestureDetector(
    onTap: () {
    this._dismissKeyboard(context);
    },
    child: new Container(
    color: Colors.white,
    child: new Column(
        children: <Widget>[/*...*/],
    ),
    ),
 );
}

0

tente usar um controlador de edição de texto. no começo,

    final myController = TextEditingController();
     @override
  void dispose() {
    // Clean up the controller when the widget is disposed.
    myController.dispose();
    super.dispose();
  }

e no evento na imprensa,

onPressed: () {
            commentController.clear();}

isso descartará o teclado.


0

Para resumir, esta é uma solução funcional para o Flutter 1.17:

Envolva seu widget assim:

GestureDetector(
        onTap: FocusScope.of(context).unfocus,
        child: YourWidget(),
);
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.