Come posso chiudere la tastiera sullo schermo?


139

Sto raccogliendo l'input dell'utente con a TextFormFielde quando l'utente preme a per FloatingActionButtonindicare che ha finito, desidero chiudere la tastiera sullo schermo.

Come faccio a disattivare automaticamente la tastiera?

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, La seconda risposta di @Pascal dovrebbe essere la risposta aggiornata e corretta.
Jack

Risposte:


226

A partire da Flutter v1.7.8 + hotfix.2, la strada da percorrere è:

FocusScope.of(context).unfocus()

Commenta su PR su questo:

Ora che # 31909 (be75fb3) è atterrato, dovresti usare al FocusScope.of(context).unfocus()posto di FocusScope.of(context).requestFocus(FocusNode()), poiché FocusNodes sono ChangeNotifierse dovrebbero essere smaltiti correttamente.

-> NON usare ̶r̶e̶q̶u̶e̶s̶t̶F̶o̶c̶u̶s̶(̶F̶o̶c̶u̶s̶N̶o̶d̶e̶(̶)̶più.

 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
Ha funzionato per me su hotfix v1.7.8 + hotfix.4
Rajesh Jr.

2
funziona per me, questa risposta dovrebbe essere mascherata come quella corretta
user3087360

@kine puoi approfondire per favore? Secondo la documentazione, questo è il modo di fare (vedere api.flutter.dev/flutter/widgets/FocusNode/unfocus.html )
Pascal

@Pascal Sì, ho letto la documentazione e questa sarebbe stata la mia soluzione preferita, ma nella mia app non funziona sempre (un modulo piuttosto complesso con diversi se TextFieldaltri widget di modifica). Non so perché ma a volte unfocusnon ha alcun effetto. Sostituirlo con la soluzione accettata (senza altre modifiche) risolve il problema. Forse è correlato alla posizione da cui unfocusviene chiamato. Devo chiamarlo ad esempio da CheckBoxListTile.onChangedper chiudere la tastiera quando l'utente interagisce con un widget casella di controllo e da altre posizioni simili. Non ricordo la posizione esatta del problema.
kine

@kine Grazie per la spiegazione. Fornire un esempio al team Flutter sarebbe fantastico ;-)
Pascal

207

Nota: questa risposta è obsoleta. Vedi la risposta per le versioni più recenti di Flutter .

Puoi chiudere la tastiera togliendo il focus di TextFormFielde dandola a un inutilizzato FocusNode:

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

Dove implementeresti questo codice? Nel TextFormField; forse dopo onChanged:o nell'azione del tuo pulsante personalizzato?
Charles Jr

@CharlesJr Lo faccio nell'azione del mio pulsante.
Duncan Jones

puoi usare il mio pacchetto se vuoi :) pub.dartlang.org/packages/keyboard_actions
diegoveloper

17
Questo è prima di Flutter v1.7.8 - vedi risposta stackoverflow.com/a/56946311/8696915 che dàFocusScope.of(context).unfocus()
Richard Johnson

1
Non farlo se hai accesso a .unfocus () poiché causerà una perdita di memoria. Quel nuovo FocusNode () non verrà mai ripulito. Vedi commento su .unfocus ()
Michael Peterson,

70

La soluzione con FocusScope non funziona per me. Ne ho trovato un altro:

import 'package:flutter/services.dart';

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

Ha risolto il mio problema.


Chiamare questo non nasconde la tastiera per me. Dovrebbe funzionare sia su Android che su iOS?
Jardo

Ha funzionato per me su iOS (12.1, iPhone 5s) e Android (Pixel 3)
Jannie Theunissen

Dove lo metti? Ho provato ad aggiungerlo come primo bit di codice nell'app e non ha fatto nulla.
Justin808

Cosa intendi con "il primo bit di codice"? Inseriscilo nel buildmetodo per esempio.
Andrey Turkovsky,

1
c'è un equivalente per questo per il keybaord numerico?
Daniel Maksimovich,

19

Per Flutter 1.17.3 (canale stabile a giugno 2020), utilizzare

FocusManager.instance.primaryFocus.unfocus();

12

Nessuna delle soluzioni di cui sopra non funziona per me.

Flutter lo suggerisce: metti il ​​tuo widget all'interno del nuovo GestureDetector () su cui il tocco nasconderà la tastiera e onTap usa FocusScope.of (contesto) .requestFocus (nuovo 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

Il codice seguente mi ha aiutato a nascondere la tastiera

   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'),
    ),
  ), })

prova questo con il gesto del tocco


Grazie ... ho preso questa soluzione
Ajay Kumar

6

Poiché in Flutter tutto è un widget, ho deciso di racchiudere SystemChannels.textInput.invokeMethod('TextInput.hide');l' FocusScope.of(context).requestFocus(FocusNode());approccio e in un breve modulo di utilità con un widget e un mixin al suo interno.

Con il widget, puoi avvolgere qualsiasi widget (molto comodo quando si utilizza un buon supporto IDE) con il 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(),
    );
  }
}

Con il mixin, puoi attivare nascondendo la tastiera da qualsiasi stato o widget su qualsiasi interazione:

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 creare un keyboard_hider.dartfile e il widget e il mixin sono pronti per l'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

Puoi usare il unfocus()metodo della 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
Ciao! Sarebbe meglio se potessi modificare la tua risposta per aggiungere solo un po 'più di contesto alla tua risposta.
grooveplex

1
La migliore soluzione con il minor numero di codici
Val

Sì, rimuove il focus se si tocca un widget specifico. Non posso aggiungerlo a tutti i widget sulla mia app.
Dpedrinha

Toccando un widget è solo un modo per chiamare il unfocusmetodo. Se non vuoi inviare spam alla tua app, puoi utilizzare un modo diverso, come l' TextFormFieldevento di modifica o un pattern reattivo, dipende dall'architettura della tua app.
Evandro Ap. S.

4

Sembra approcci diversi per versioni diverse. Sto usando Flutter v1.17.1 e quanto segue funziona per me.

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

prova a utilizzare un controller di modifica del testo. in principio,

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

e nell'evento sulla stampa,

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

questo eliminerà la tastiera.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.