在聚焦SingleChildScrollView
的情况下滚动TextFormField
时,我想隐藏键盘。我在NotificationListener<ScrollNotification>
的顶部添加了SingleChildScrollView
,并收听ScrollStartNotification
。然后,我打电话给FocusScope.of(context).requestFocus(FocusNode())
隐藏键盘。
TextFormField
位于屏幕底部时,会发生此问题。当我单击它并获得焦点时,键盘将出现并向上移动SingleChildScrollView
,这将再次触发ScrollStartNotification
并隐藏键盘。
答案 0 :(得分:9)
ScrollView
小部件现在具有可用于此目的的 keyboardDismissBehavior
属性。该属性由 ListView
、GridView
和 CustomScrollView
继承。
该属性默认为 ScrollViewKeyboardDismissBehavior.manual
,但可以更改为 ScrollViewKeyboardDismissBehavior.onDrag
。
https://api.flutter.dev/flutter/widgets/ScrollView/keyboardDismissBehavior.html
示例
ListView.builder(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
itemCount: itemCount,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text('Item ${index + 1}'),
);
},
)
至少在撰写本文时,Flutter 稳定分支中的 CustomScrollView
尚未将该属性传递给其父级,但已添加此属性的 pull request于 2020 年 9 月 21 日合并到 master 中,可能很快就会可用。
答案 1 :(得分:4)
与其使用NotificationListener进行包装,不如将您的SingleChildScrollView包裹在GestureDetector内并关闭键盘,如下所示:
GestureDetector(
behavior: HitTestBehavior.opaque,
onPanDown: (_) {
FocusScope.of(context).requestFocus(FocusNode());
},
child: SingleChildScrollView(...),
);
答案 2 :(得分:3)
我们创建了这个简单的小部件。 在此小部件中包装可滚动视图,您就完成了。
/// A widget that listens for [ScrollNotification]s bubbling up the tree
/// and close the keyboard on user scroll.
class ScrollKeyboardCloser extends StatelessWidget {
final Widget child;
ScrollKeyboardCloser({@required this.child});
@override
Widget build(BuildContext context) {
return NotificationListener<ScrollNotification>(
onNotification: (scrollNotification) {
if (scrollNotification is UserScrollNotification) {
// close keyboard
FocusScope.of(context).unfocus();
}
return false;
},
child: child,
);
}
}
答案 3 :(得分:1)
我认为最好使用NotificationListener
听滚动,而不是仅点击
NotificationListener(
// ignore: missing_return
onNotification: (notification) {
if (notification is ScrollUpdateNotification) {
if (notification.scrollDelta.abs() > 10 &&
notification.dragDetails != null)
FocusScope.of(context).unfocus();
}
},
child: SingleChildScrollView(
child: SomeChildWidget(),
),
)
答案 4 :(得分:0)
与GestureDetector和onPanDown有关的大多数答案都不错,但对我来说还不够。玩了一点之后,我想我找到了一个更好的解决方案。
GestureDetector(
onVerticalDragUpdate: (details) {
if (details.primaryDelta > 20) {
FocusScope.of(context).detach();
}
},
child: Widget(),
);
如果向上滑动增量为负数,则不会触发撤消,如果您真正缓慢滑动也是如此。您显然可以调整增量,以使其或多或少地响应。
另外,detach()
方法看起来比提供新的FocusScope更好。
答案 5 :(得分:0)
GestureDetector仅适用于“单次点击”,这并不代表所有可以执行的手势。 侦听器侦听可以构造手势的事件,例如按下,移动,释放或取消指针的时间。
Listener(
onPointerDown: (_) {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.focusedChild.unfocus();
}
},
child: MaterialApp(...),
);
答案 6 :(得分:0)
这是我写的东西来处理这个问题。我的目标是在您像在 Iphone 上一样滑动时隐藏键盘
Widget swipeOffKeyboard(BuildContext context, {Widget? child}) {
return Listener(
onPointerMove: (PointerMoveEvent pointer) {
disKeyboard(pointer, context);
},
child: child, // your content should go here
);
}
void disKeyboard(PointerMoveEvent pointer, BuildContext context) {
double insets = MediaQuery.of(context).viewInsets.bottom;
double screenHeight = MediaQuery.of(context).size.height;
double position = pointer.position.dy;
double keyboardHeight = screenHeight - insets;
if (position > keyboardHeight && insets > 0) FocusManager.instance.primaryFocus?.unfocus();
}