Android 键盘接收不到点击事件解决!

353 阅读2分钟

场景:今天遇到软键盘移动到其他位置之后,点击软键盘上的字母接收不到点击事件。

猜测一:系统默认把软键盘的触摸区域给写死了,只能在屏幕的底部。
验证猜测一:我把键盘输入部分的布局设至全屏,结果全屏的软键盘是可以接收得到点击事件的。所以软键盘的触摸区域不是写死不变的。而是根据软键盘的大小来设置的。根据平常的经验设置了触摸事件监听之后,在view的宽高范围内应该都是可以接收到触摸事件才对。但是现在即使是点击view所在的范围也不能接收到这个监听的事件。

然后我又把软键盘横向范围缩小至原来的一半,结果点击另外一半的地方出现了错误。(这个问题未深究未解决)

普及:在创建window的时候,系统会为每个window设置固定的触摸区域,这个区域是由Frame确定的。系统在获取键盘的Frame的时候只能获取到键盘按键区域的大小。所以把键盘移动之后,没有在这块设置的区域就接收不到点击事件。
Android 11的源码:WindowState.java类的3418行getTouchableRegion()方法中设置了触摸范围。

/** Get the touchable region in global coordinates. */

void getTouchableRegion(Region outRegion) {

final Rect frame =mWindowFrames.mFrame;

switch (mTouchableInsets) {

default:

case TOUCHABLE_INSETS_FRAME:

outRegion.set(frame);

break;

case TOUCHABLE_INSETS_CONTENT:

applyInsets(outRegion,frame,mGivenContentInsets);

break;

case TOUCHABLE_INSETS_VISIBLE:

applyInsets(outRegion,frame,mGivenVisibleInsets);

break;

case TOUCHABLE_INSETS_REGION: { //主要是这个case。这个case中做了触摸范围的设置。

outRegion.set(mGivenTouchableRegion);//这里设置了触摸的范围。如果要全屏接收那这个参数就得设置全屏的范围,键盘默认的不是全屏范围。

outRegion.translate(frame.left,frame.top);

break;

}

}

cropRegionToStackBoundsIfNeeded(outRegion);

subtractTouchExcludeRegionIfNeeded(outRegion);

}

修改WindowState.java类的3418行getTouchableRegion()内部设置触摸范围的方案:
outRegion.set(mGivenTouchableRegion); 把这个mGivenTouchableRegion 换成自己创建的全屏范围的Region对象即可。但是要进行包名判断,是键盘的包名才进行全屏的设置。

mAttrs.packageName这个可以获取到对应window的包名。

最终代码:frameworks/base/services/core/java/com/android/server/wm/WindowState.java 源码路径下的getTouchableRegion

/** Get the touchable region in global coordinates. */
    void getTouchableRegion(Region outRegion) {
        final Rect frame = mWindowFrames.mFrame;
        switch (mTouchableInsets) {
            default:
            case TOUCHABLE_INSETS_FRAME:
                outRegion.set(frame);
                break;
            case TOUCHABLE_INSETS_CONTENT:
                applyInsets(outRegion, frame, mGivenContentInsets);
                break;
            case TOUCHABLE_INSETS_VISIBLE:
                applyInsets(outRegion, frame, mGivenVisibleInsets);
                break;
            case TOUCHABLE_INSETS_REGION: {
    if(inputFilter()){
      outRegion.set(new Region(0, 0, frame.right, frame.bottom));//这是后添加的。解决键盘touchableRegion没有全屏的问题
    }else{
    outRegion.set(mGivenTouchableRegion);//这是系统默认设置的touchableRegion
    }
                outRegion.translate(frame.left, frame.top);
                break;
            }
        }
        cropRegionToStackBoundsIfNeeded(outRegion);
        subtractTouchExcludeRegionIfNeeded(outRegion);
    }
//过滤输入法的包名 
private boolean inputFilter(){
  if(mAttrs!=null&&mAttrs.packageName!=null
  &&mAttrs.packageName.equals("com.android.inputmethod.latin")){
  return true;
  }
  return false;
}

设置好之后,键盘随意移动到哪里都可以接收到触摸事件了。但是这种策略就改变了系统原来对应键盘的触摸策略了。