Jak mogę zamknąć klawiaturę ekranową?

140

Zbieram dane wejściowe użytkownika za pomocą a, TextFormFielda gdy użytkownik naciśnie a, FloatingActionButtonco oznacza, że ​​są gotowe, chcę odrzucić klawiaturę ekranową.

Jak wyłączyć automatyczne wyłączanie klawiatury?

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 Jackson
źródło
Collin, Druga odpowiedź z @Pascal powinna być zaktualizowaną, poprawioną odpowiedzią.
Jack

Odpowiedzi:

235

Od Flutter w wersji 1.7.8 + poprawka 2, droga jest następująca:

FocusScope.of(context).unfocus()

Skomentuj PR o tym:

Teraz, gdy # 31909 (be75fb3) wylądował, powinieneś użyć FocusScope.of(context).unfocus()zamiast FocusScope.of(context).requestFocus(FocusNode()), ponieważ FocusNodes są ChangeNotifiersi powinny zostać usunięte prawidłowo.

-> NIE używaj ̶r̶e̶q̶u̶e̶s̶t̶F̶o̶c̶u̶s̶(̶F̶o̶c̶u̶s̶N̶o̶d̶e̶(̶)̶już.

 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̶(̶)̶)̶;̶
Pascal
źródło
1
Pracował dla mnie nad poprawką v1.7.8 + poprawka 4
Rajesh Jr.
2
działa dla mnie, ta odpowiedź powinna być zamaskowana jako poprawna
user3087360
@kine, czy możesz to rozwinąć? Zgodnie z dokumentacją, jest to sposób na zrobienie tego (patrz api.flutter.dev/flutter/widgets/FocusNode/unfocus.html )
Pascal
@Pascal Tak, przeczytałem dokumentację i byłoby to moje preferowane rozwiązanie, ale w mojej aplikacji nie zawsze działa (dość złożony formularz z kilkoma TextFieldi innymi widżetami edycji). Nie wiem dlaczego, ale czasami unfocusnie daje to żadnego efektu. Zastąpienie go zaakceptowanym rozwiązaniem (bez innych zmian) rozwiązuje problem. Może jest to związane z lokalizacją, z której unfocusdzwoniono. Muszę to wywołać np. Z, CheckBoxListTile.onChangedaby zamknąć klawiaturę, gdy użytkownik wchodzi w interakcję z widżetem pola wyboru oraz z innych podobnych lokalizacji. Nie pamiętam dokładnej lokalizacji problemu.
kine
@kine Dzięki za wyjaśnienie. Danie przykładu zespołowi Flutter byłoby niesamowite ;-)
Pascal
210

Uwaga: ta odpowiedź jest nieaktualna. Zobacz odpowiedź na nowsze wersje Fluttera .

Możesz odrzucić klawiaturę, usuwając fokus TextFormFieldi przekazując ją nieużywanemu FocusNode:

FocusScope.of(context).requestFocus(FocusNode());
Collin Jackson
źródło
Gdzie zaimplementowałbyś ten kod? W TextFormField; może po onChanged:lub w akcji niestandardowego przycisku?
Charles Jr
@CharlesJr Robię to w akcji mojego przycisku.
Duncan Jones
możesz użyć mojego pakietu, jeśli chcesz :) pub.dartlang.org/packages/keyboard_actions
diegoveloper
17
To jest przed Flutter w wersji 1.7.8 - patrz odpowiedź stackoverflow.com/a/56946311/8696915, która zawieraFocusScope.of(context).unfocus()
Richard Johnson,
1
Nie rób tego, jeśli masz dostęp do .unfocus (), ponieważ spowoduje to wyciek pamięci. Ten nowy FocusNode () nigdy nie zostanie wyczyszczony. Zobacz komentarz dotyczący domeny .unfocus ()
Michael Peterson
70

Rozwiązanie z FocusScope nie działa dla mnie. Znalazłem inny:

import 'package:flutter/services.dart';

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

To rozwiązało mój problem.

Andrey Turkovsky
źródło
Wywołanie tego nie ukrywa dla mnie klawiatury. Czy powinien działać zarówno na Androida, jak i iOS?
Jardo
Pracował dla mnie na iOS (12.1, iPhone 5s) i Android (Pixel 3)
Jannie Theunissen
Gdzie to położyłeś? Próbowałem po prostu dodać go jako pierwszy fragment kodu w aplikacji i nic nie dało.
Justin808
Co masz na myśli - „pierwszy bit kodu”? Na przykład wstaw go do buildmetody.
Andrey Turkovsky
1
czy istnieje odpowiednik tego dla klawiatury numerycznej?
Daniel Maksimovich
20

W przypadku Fluttera 1.17.3 (stabilny kanał od czerwca 2020 r.) Użyj

FocusManager.instance.primaryFocus.unfocus();
suztomo
źródło
12

Żadne z powyższych rozwiązań nie działa dla mnie.

Flutter sugeruje to - umieść swój widget w nowym GestureDetector (), na którym dotknięcie spowoduje ukrycie klawiatury, a onTap użyje FocusScope.of (kontekst) .requestFocus (nowy 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;
}}
aamitarya
źródło
12

Poniższy kod pomógł mi ukryć klawiaturę

   void initState() {
   SystemChannels.textInput.invokeMethod('TextInput.hide');
   super.initState();
   }
poonam
źródło
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'),
    ),
  ), })

spróbuj tego gestem dotknięcia

karan champaneri
źródło
Dzięki ... wziąłem to rozwiązanie
Ajay Kumar
6

Ponieważ we Flutterze wszystko jest widżetem, postanowiłem zawrzeć SystemChannels.textInput.invokeMethod('TextInput.hide');i FocusScope.of(context).requestFocus(FocusNode());podejście w krótkim module narzędziowym z widżetem i mieszanką w nim.

Za pomocą widżetu możesz owinąć dowolny widżet (bardzo wygodny przy korzystaniu z dobrej obsługi IDE) KeyboardHiderwidżetem:

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(),
    );
  }
}

Dzięki miksowaniu możesz wywołać ukrycie klawiatury przed dowolnym stanem lub widżetem podczas dowolnej interakcji:

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, ...
      },
    );
  }
}

Po prostu utwórz keyboard_hider.dartplik, a widżet i mixin będą gotowe do użycia:

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,
    );
  }
}
Vince Varga
źródło
4

Możesz użyć unfocus()metody z FocusNodeklasy.

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());
}
Evandro Ap. S.
źródło
1
Cześć! Byłoby najlepiej, gdybyś mógł edytować swoją odpowiedź, aby dodać trochę więcej kontekstu do odpowiedzi.
grooveplex
1
Najlepsze rozwiązanie z najmniejszą ilością kodowania
Val
Tak, usuwa fokus po dotknięciu określonego widżetu. Nie mogę dodać tego do każdego widżetu w mojej aplikacji.
Dpedrinha
Stuknięcie w widżet to tylko jeden ze sposobów wywołania unfocusmetody. Jeśli nie chcesz spamować tego w swojej aplikacji, możesz użyć innego sposobu, na przykład TextFormFieldzdarzenia zmiany lub wzorca reaktywnego, zależy to od architektury aplikacji.
Evandro Ap. S.
4

Wygląda na to, że różne podejścia do różnych wersji. Używam Fluttera w wersji 1.17.1 i poniższe działa dla mnie.

onTap: () {
    FocusScopeNode currentFocus = FocusScope.of(context);
    if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
       currentFocus.focusedChild.unfocus();
    }
}
dbyuvaraj
źródło
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>[/*...*/],
    ),
    ),
 );
}
Amit Prajapati
źródło
0

spróbuj użyć kontrolera edycji tekstu. na początku,

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

a podczas wydarzenia prasowego

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

spowoduje to odrzucenie klawiatury.

CHANDUKA SAMARASINGHE.
źródło
0

Podsumowując, jest to działające rozwiązanie dla Fluttera 1.17:

Owiń swój widżet w ten sposób:

GestureDetector(
        onTap: FocusScope.of(context).unfocus,
        child: YourWidget(),
);
Valentin Seehausen
źródło