在Flutter中滚动时隐藏键盘

时间:2019-03-22 19:48:01

标签: flutter

在聚焦SingleChildScrollView的情况下滚动TextFormField时,我想隐藏键盘。我在NotificationListener<ScrollNotification>的顶部添加了SingleChildScrollView,并收听ScrollStartNotification。然后,我打电话给FocusScope.of(context).requestFocus(FocusNode())隐藏键盘。

TextFormField位于屏幕底部时,会发生此问题。当我单击它并获得焦点时,键盘将出现并向上移动SingleChildScrollView,这将再次触发ScrollStartNotification并隐藏键盘。

7 个答案:

答案 0 :(得分:9)

ScrollView 小部件现在具有可用于此目的的 keyboardDismissBehavior 属性。该属性由 ListViewGridViewCustomScrollView 继承。

该属性默认为 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();
}