Как я могу отключить экранную клавиатуру?

141

Я собираю пользовательский ввод с помощью, TextFormFieldи когда пользователь нажимает FloatingActionButtonкнопку, указывающую, что они выполнены, я хочу закрыть экранную клавиатуру.

Как отключить автоматическое отключение клавиатуры?

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());
}
Коллин Джексон
источник
Коллин, второй ответ от @Pascal должен быть обновленным, исправленным.
Джек

Ответы:

236

Начиная с Flutter v1.7.8 + hotfix.2, можно сделать следующее:

FocusScope.of(context).unfocus()

Прокомментируйте PR по этому поводу:

Теперь, когда приземлился # 31909 (be75fb3), вы должны использовать FocusScope.of(context).unfocus()вместо FocusScope.of(context).requestFocus(FocusNode()), так как FocusNodes есть ChangeNotifiersи должны быть удалены должным образом.

-> НЕ используйте ̶r̶e̶q̶u̶e̶s̶t̶F̶o̶c̶u̶s̶(̶F̶o̶c̶u̶s̶N̶o̶d̶e̶(̶)̶больше.

 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
У меня работал над исправлением v1.7.8 + hotfix.4
Раджеш-младший,
2
работает для меня, этот ответ должен быть замаскирован как правильный
user3087360
@kine, не могли бы вы уточнить? Согласно документации, это способ сделать (см. Api.flutter.dev/flutter/widgets/FocusNode/unfocus.html )
Паскаль
@Pascal Да, я прочитал документацию, и это было бы моим предпочтительным решением, но в моем приложении оно работает не всегда (довольно сложная форма с несколькими TextFields и другими виджетами редактирования). Не знаю почему, но иногда unfocusне дает никакого эффекта. Замена на принятое решение (без других изменений) устраняет проблему. Может быть, это связано с местом, откуда unfocusзвонят. Мне нужно вызвать его, например, CheckBoxListTile.onChangedчтобы закрыть клавиатуру, когда пользователь взаимодействует с виджетом флажка, и из других подобных мест. Я не помню точное местонахождение проблемы.
kine
@kine Спасибо за объяснение. Было бы замечательно подать пример команде Flutter ;-)
Паскаль,
211

Примечание: этот ответ устарел. См. Ответ для новых версий Flutter .

Вы можете убрать клавиатуру, убрав фокус TextFormFieldи отдав ее неиспользуемым FocusNode:

FocusScope.of(context).requestFocus(FocusNode());
Коллин Джексон
источник
Где бы вы реализовали этот код? В TextFormField; может быть, после onChanged:или в действии вашей пользовательской кнопки?
Чарльз мл.
@CharlesJr Я делаю это по нажатию кнопки.
Дункан Джонс
вы можете использовать мой пакет, если хотите :) pub.dartlang.org/packages/keyboard_actions
diegoveloper
17
Это было до Flutter v1.7.8 - см. Ответ stackoverflow.com/a/56946311/8696915, который даетFocusScope.of(context).unfocus()
Ричард Джонсон,
1
Не делайте этого, если у вас есть доступ к .unfocus (), поскольку это вызовет утечку памяти. Этот новый FocusNode () никогда не очистится. См. Комментарий о .unfocus ()
Майкл Петерсон
70

Решение с FocusScope мне не подходит. Нашел другой:

import 'package:flutter/services.dart';

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

Это решило мою проблему.

Андрей Турковский
источник
Вызов этого не скрывает для меня клавиатуру. Должен ли он работать как на Android, так и на iOS?
Жардо
Работала у меня на iOS (12.1, iPhone 5s) и Android (Pixel 3)
Дженни
Куда вы это положили? Я попытался просто добавить его в качестве первого фрагмента кода в приложение, но он ничего не сделал.
Justin808
Что значит «первая часть кода»? Вставьте его, например, в buildметод.
Андрей Турковский
1
есть ли эквивалент для числовой клавиатуры?
Даниил Максимович
21

Для Flutter 1.17.3 (стабильный канал по состоянию на июнь 2020 г.) используйте

FocusManager.instance.primaryFocus.unfocus();
Suztomo
источник
13

Следующий код помог мне скрыть клавиатуру

   void initState() {
   SystemChannels.textInput.invokeMethod('TextInput.hide');
   super.initState();
   }
пунам
источник
Для меня это сработало лучше, чем решение добавить FocusScope.of (context) .unfocus (), поскольку это решение поставило меня в цикл отображения и скрытия клавиатуры
Варун
13

Пример реализации .unfocus () для автоматического скрытия клавиатуры при прокрутке списка

FocusScope.of(context).unfocus();

вы можете найти на

https://github.com/flutter/flutter/issues/36869#issuecomment-518118441

Благодаря szotp

Томаш Сильный
источник
1
Ага, это самый простой способ сделать это.
Митхун Натх,
12

Ни одно из вышеперечисленных решений не работает для меня.

Flutter предлагает это - поместите свой виджет в новый GestureDetector (), касание которого будет скрывать клавиатуру, а onTap использует FocusScope.of (context) .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;
}}
амитарья
источник
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'),
    ),
  ), })

попробуйте этот жест касания

Каран Чампанери
источник
Спасибо ... принял это решение
Аджай Кумар
6

Поскольку во Flutter все является виджетом, я решил обернуть подход SystemChannels.textInput.invokeMethod('TextInput.hide');и FocusScope.of(context).requestFocus(FocusNode());подход в небольшой служебный модуль с виджетом и миксином в нем.

С помощью виджета вы можете обернуть любой виджет (очень удобно при использовании хорошей поддержки IDE) с помощью KeyboardHiderвиджета:

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

С помощью миксина вы можете запустить скрытие клавиатуры из любого состояния или виджета при любом взаимодействии:

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

Просто создайте keyboard_hider.dartфайл, и виджет и миксин готовы к использованию:

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

Вы можете использовать unfocus()метод из FocusNodeкласса.

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. С.
источник
1
Здравствуй! Было бы лучше, если бы вы могли отредактировать свой ответ, чтобы добавить к нему немного больше контекста.
grooveplex
1
Лучшее решение с наименьшим количеством кода
Val
Да, он удаляет фокус при нажатии на определенный виджет. Не могу добавить его к каждому виджету в моем приложении.
Dpedrinha
Нажатие на виджет - это всего лишь один из способов вызова unfocusметода. Если вы не хотите спамить это в своем приложении, вы можете использовать другой способ, например TextFormFieldсобытие изменения или реактивный шаблон, это зависит от архитектуры вашего приложения.
Evandro Ap. S.
4

Похоже, разные подходы для разных версий. Я использую Flutter v1.17.1, и у меня работает следующее.

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>[/*...*/],
    ),
    ),
 );
}
Амит Праджапати
источник
1

Чтобы закрыть клавиатуру (1.7.8 + hotfix.2 и выше), просто вызовите метод ниже:

FocusScope.of(context).unfocus();

После того, как метод FocusScope.of (context) .unfocus () уже проверяет, есть ли фокус, прежде чем закрыть клавиатуру, нет необходимости проверять его раньше. Если вам это нужно, просто вызовите другой контекстный метод: FocusScope.of(context).hasPrimaryFocus

Кассио Сеффрин
источник
0

попробуйте использовать контроллер для редактирования текста. в начале,

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

и на мероприятии для прессы,

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

это закроет клавиатуру.

ЧАНДУКА САМАРАСИНГЕ.
источник
0

Подводя итог, это рабочее решение для Flutter 1.17:

Оберните свой виджет следующим образом:

GestureDetector(
        onTap: FocusScope.of(context).unfocus,
        child: YourWidget(),
);
Валентин Зеехаузен
источник