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.