Flutter键盘弹出关闭监听

遇到问题

在使用PinCodeField验证码控件的时候遇到一个问题,在Android上边,点击返回或者点击键盘右上角的关闭键盘是不会触发PinCodeField失去焦点的所以导致关闭键盘之后,PinCodeField一直处于获取焦点的状态,无法再次点击使PinCodeField获取焦点弹出键盘,所以我们要监听键盘的弹出和关闭去设置相应的焦点状态。

解决方案

第一种使用keyboard_visibility三方库

keyboard_visibility键盘弹出关闭监听

这个开发者已经很久没更新了,所以我把代码拉到本地,到时候不兼容的时候方便自己修改。

使用的话以拉到本地依赖为准,把它放到和我们的主项目同一个目录下用下边的方式依赖:

keyboard_visibility:
    path: ../flutter_keyboard_visibility

使用:

import 'package:keyboard_visibility/keyboard_visibility.dart';


 int subscribeId;

 @protected
 void initState() {
   super.initState();
   subscribeId = KeyboardVisibilityNotification().addNewListener(
     onChange: (bool visible) {
       print(visible);
     },
   );
 }

 //及时移除防止内存泄漏问题 "A LoginInputCodeViewModel was used after being disposed."
 @override
  void dispose() {
    KeyboardVisibilityNotification().removeListener(subscribeId);
    super.dispose();
  }

如果你在使用作者老版本过程中遇到以下问题:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':keyboard_visibility:verifyReleaseResources'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
   > 1 exception was raised by workers:
     com.android.builder.internal.aapt.v2.Aapt2Exception: Android resource linking failed
     C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\da95e0dd41fd0c634661df2a0f122634\core-1.1.0\res\values\values.xml:142:5-173:25: AAPT: error: resource android:attr/fontVariationSettings not found.

     C:\Users\Administrator\.gradle\caches\transforms-2\files-2.1\da95e0dd41fd0c634661df2a0f122634\core-1.1.0\res\values\values.xml:142:5-173:25: AAPT: error: resource android:attr/ttcIndex not found.

请把keyboard_visibility目录下build.gradle中的compileSdkVersion从27修改为28即可:
在这里插入图片描述

keyboard_visibility详细使用,这个fork的库里已经对上边的问题处理了

第二种使用WidgetsBindingObserver & didChangeMetrics

WidgetsBindingObserver这个组件可以监听页面的一些生命周期,并且其中有一个回调didChangeMetrics可以监听界面高度的变化。其中键盘的弹出和收起这些其实都属于高度的变化自然也是可以监听到的。

使用:

class _PinCodeTextFieldState extends State<PinCodeTextField> with WidgetsBindingObserver {

  bool isKeyboardActived = false;

 @protected
void initState() {
 //根据autoFocus赋予isKeyboardActived初值,自动获取焦点的话键盘是自动弹出的需要赋值为true正好和autoFocus对应
 isKeyboardActived = widget.autoFocus;
 WidgetsBinding.instance.addObserver(this);
   super.initState();
}

@override
  void didChangeMetrics() {
    super.didChangeMetrics();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      // 当前是安卓系统并且在焦点聚焦的情况下
      if (Platform.isAndroid && _focusNode.hasFocus) {
        if (isKeyboardActived) {
          isKeyboardActived = false;
          // 使输入框失去焦点
          _focusNode.unfocus();
          return;
        } else {
//          showToast("键盘弹出 false");
        }
        isKeyboardActived = true;
      } else {
        isKeyboardActived = false;
//        showToast("键盘消失");
      }
    });
  }

 @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

具体和PinCodeTextField结合使用在下边:

class PinCodeTextField extends StatefulWidget {
 
  /// If the pin code field should be autofocused or not. Default is [false]
  final bool autoFocus;

  /// Should pass a [FocusNode] to manage it from the parent
  final FocusNode focusNode;

  PinCodeTextField({
    Key key,
    //省略代吗...
    this.autoFocus = false,
    this.focusNode,
	//省略代吗...
  }) : super(key: key);
}

class _PinCodeTextFieldState extends State<PinCodeTextField>
    with WidgetsBindingObserver {//重点
  FocusNode _focusNode;
  bool isKeyboardActived = false;

  @override
  void initState() {
	 //重点
    isKeyboardActived = widget.autoFocus;
    //重点
    WidgetsBinding.instance.addObserver(this);
    _focusNode = widget.focusNode ?? FocusNode();
    _focusNode.addListener(() {
      setState(() {});
    }); 
    super.initState();
  }

  // validating all the values
  void _checkForInvalidValues() {
   //省略代吗...
  }


  @override
  void dispose() {
    _textEditingController.dispose();
    _focusNode.dispose();
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }


  @override
  Widget build(BuildContext context) {
    return Stack(
    	//省略代吗...
        GestureDetector(
          onTap: _onFocus,
        	//省略代吗...
          child: Container(
            //省略代吗...
          ),
        ),
      ],
    );
  }
   //重点
  @override
  void didChangeMetrics() {
    super.didChangeMetrics();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      // 当前是安卓系统并且在焦点聚焦的情况下
      if (Platform.isAndroid && _focusNode.hasFocus) {
        if (isKeyboardActived) {
          isKeyboardActived = false;
          // 使输入框失去焦点
          _focusNode.unfocus();
          return;
        } else {
//          showToast("键盘弹出 false");
        }
        isKeyboardActived = true;
      } else {
        isKeyboardActived = false;
//        showToast("键盘消失");
      }
    });
  }
 //重点
  void _onFocus() {
    if (_focusNode.hasFocus) {
//      showToast("点击 hasFocus");
      _focusNode.unfocus();
    } else {
//      showToast("点击 noFocus");
      FocusScope.of(context).requestFocus(_focusNode);
    }
  }
}

参考:flutter键盘弹出关闭监听

猜你喜欢

转载自blog.csdn.net/u011148116/article/details/106902318