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

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

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.


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


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;
}}

12

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

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

spróbuj tego gestem dotknięcia


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

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

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

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

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.


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(),
);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.