Flutter自定义Widget-可以监听键盘高度的TextField

现在我们有个需求,要求输入完成后所有字母都转大写,看起来很容易,直接写个TextField,然后在onEditingComplete里处理不就行了,但是,你会发现,键盘里还有个下拉按钮,就上面那个按钮,点击它虽然键盘消失了,但根本不执行onEditingComplete,只有点击下面那个按钮才会执行,这样测试肯定不通过,那就在onChange方法里处理?也不行,因为我输入完成后还得访问后台接口,所以不能在onChange方法里处理。

背景讲完了,上代码:

1,使用扩展类extension...on...,扩展下TextField,混入class WidgetsBindingObserver来监听界面的变化,具体监听尺寸变化的方法是didChangeMetrics()

extension TextFieldExtension on TextField{

  Widget getKeyboardListenerTextField(){
    if(focusNode == null) return this;
    return KeyboardListenerTextField(child: this);
  }

}
class KeyboardListenerTextField extends StatefulWidget {
  TextField child;
  KeyboardListenerTextField({
     this.child,
  });

  @override
  _KeyboardListenerTextFieldState createState() => _KeyboardListenerTextFieldState();
}

class _KeyboardListenerTextFieldState extends State<KeyboardListenerTextField> with WidgetsBindingObserver {
  //标记键盘是否现实中,默认不显示
  bool isKeyboardActived = false;
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }
  @override
  void dispose() {
    super.dispose();
    WidgetsBinding.instance.removeObserver(this);
    widget.child.focusNode.unfocus();
  }

  @override
  void didChangeMetrics() {
    super.didChangeMetrics();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      // 当前是安卓系统并且在焦点聚焦的情况下
      if (Platform.isAndroid && widget.child.focusNode.hasFocus) {
        if (isKeyboardActived) {
          isKeyboardActived = false;
          // 使输入框失去焦点
          widget.child.focusNode.unfocus();
          return;
        }
        isKeyboardActived = true;
      } else {
        isKeyboardActived = false;
      }
    });
  }
  @override
  Widget build(BuildContext context) {
    return widget.child;
  }
}

2,在使用时直接 

TextField(
  focusNode: focusNode,
  onEditingComplete: () {
    focusNode?.unfocus();
  },
  onSubmitted: (text) {
    focusNode?.unfocus();
  },
).getKeyboardListenerTextField();

3,当然,需要监听焦点

focusNode.addListener(() {
  if (!focusNode.hasFocus) {
    //失去焦点,说明输入完成,该转大写的转大写,该数据请求的数据请求
  }
});

最后:这样写也有缺点,因为如果一个界面TextField很多,如果焦点直接从这个TextField到另一个TextField,那第二个 TextField当键盘隐藏时因为键盘状态未变化,所以不会失去焦点,所以这只适合界面有一个TextField的情况。

最后的最后:如果界面就是很多TextField,那可以给整个界面混入WidgetsBindingObserver,监听整个界面的尺寸,设置监听时酱紫写:

double oldBottom = 0;
@override
void didChangeMetrics() {
  super.didChangeMetrics();
  WidgetsBinding.instance.addPostFrameCallback((_) {
    var currentBottom = MediaQuery.of(context).viewInsets.bottom;
    // 如果currentBottom为0,表示键盘消失了,这时候整个界面获取焦点,那TextField自然就失去焦点了
    // 为什么还要判断oldBottom,因为在界面没变化的时候,个别机型也会调用这个方法。。。
    // 所以必须在oldBottom不为0的时候,才获取焦点,这里坑的我好惨。。。
    if(oldBottom != 0 && currentBottom==0){
      FocusScope.of(context).requestFocus(FocusNode());
    }
    oldBottom = currentBottom;
  });
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Flutter中,可以使用以下代码来监听键盘弹起和收回事件: ```dart import 'package:flutter/services.dart'; // 监听键盘弹起和收回 final keyboardVisibilityController = KeyboardVisibilityController(); bool isKeyboardVisible = false; class KeyboardVisibilityController { final ValueNotifier<bool> visibilityNotifier = ValueNotifier<bool>(false); KeyboardVisibilityController() { // 监听键盘弹起和收回事件 SystemChannels.keyboard.addListener(_handleKeyboardVisibility); } void _handleKeyboardVisibility() { final bool isKeyboardOpen = WidgetsBinding.instance!.window.viewInsets.bottom > 0; visibilityNotifier.value = isKeyboardOpen; } void dispose() { // 移除监听 SystemChannels.keyboard.removeListener(_handleKeyboardVisibility); } } ``` 在上面的代码中,我们创建了一个 `KeyboardVisibilityController` 类来监听键盘弹起和收回事件。我们首先定义了一个 `ValueNotifier` 类型的对象 `visibilityNotifier`,用于通知键盘是否弹起。然后在构造函数中,我们调用 `SystemChannels.keyboard.addListener` 方法来添加监听器 `_handleKeyboardVisibility`,该方法将在键盘弹起和收回时被调用。在 `_handleKeyboardVisibility` 方法中,我们检查当前视图是否有底部间距,如果有,则表示键盘处于打开状态,否则表示键盘处于关闭状态。最后,我们在 `dispose` 方法中移除了监听器。 使用以上代码后,我们可以在其他 Widget监听键盘弹起和收回的事件,如下所示: ```dart class MyWidget extends StatefulWidget { @override _MyWidgetState createState() => _MyWidgetState(); } class _MyWidgetState extends State<MyWidget> { @override void initState() { super.initState(); // 监听键盘弹起和收回事件 keyboardVisibilityController.visibilityNotifier.addListener(() { setState(() { isKeyboardVisible = keyboardVisibilityController.visibilityNotifier.value; }); }); } @override void dispose() { // 移除监听 keyboardVisibilityController.visibilityNotifier.removeListener(() { setState(() { isKeyboardVisible = keyboardVisibilityController.visibilityNotifier.value; }); }); super.dispose(); } @override Widget build(BuildContext context) { return Container( child: isKeyboardVisible ? Text('键盘弹起了') : Text('键盘收回了'), ); } } ``` 在上面的代码中,我们在 `initState` 方法中添加了键盘弹起和收回的监听器,并在 `dispose` 方法中移除监听器。在 `build` 方法中,我们根据 `isKeyboardVisible` 变量来显示不同的文本内容,以便在键盘弹起或收回时进行不同的操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值