Ответ 1
Вы можете отклонить клавиатуру, убрав фокус TextFormField
и передав его неиспользованному FocusNode
:
FocusScope.of(context).requestFocus(FocusNode());
Я собираю пользовательский ввод с 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());
}
Вы можете отклонить клавиатуру, убрав фокус TextFormField
и передав его неиспользованному FocusNode
:
FocusScope.of(context).requestFocus(FocusNode());
Решение с FocusScope не работает для меня. Я нашел другое:
import 'package:flutter/services.dart';
SystemChannels.textInput.invokeMethod('TextInput.hide');
Это решило мою проблему.
Начиная с Flutter v1.7.8 + hotfix.2, есть путь:
FocusScope.of(context).unfocus()
Комментарий к пиару об этом:
Теперь, когда # 31909 (be75fb3) приземлился, вы должны использовать FocusScope.of(context).unfocus() вместо FocusScope.of(context).requestFocus(FocusNode()), так как узлы FocusNode являются ChangeNotifiers, и должны быть расположены правильно.
Ни одно из вышеперечисленных решений не работает для меня.
Flutter предлагает следующее - поместите ваш виджет в новый GestureDetector(), на котором нажатие будет скрывать клавиатуру, а по нажатию клавиши использовать 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;
}}
Возьмите GestureDetector
на верхнем уровне всех виджетов и onTap()
этого gestureDetector
и вызовите
FocusScope.of(context).requestFocus(new FocusNode());
Вы можете использовать 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());
}
Поскольку во 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,
);
}
}
Следующий код помог мне скрыть клавиатуру
void initState() {
SystemChannels.textInput.invokeMethod('TextInput.hide');
super.initState();
}
_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>[/*...*/],
),
),
);
}
Это сработало для меня:
import 'package:flutter/services.dart';
SystemChannels.textInput.invokeMethod('TextInput.hide');