Android,如何知道我的 View 被软键盘adjustPan移动了​​多少

标签 android android-layout keyboard

我有一个全屏横向应用程序 (Cocos2d-x/NDK),它有一个输入字段,我在运行时设置的位置是这样的

RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mInstance.mEditText.getLayoutParams();
params.topMargin = (int)newY;
params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
mInstance.mEditText.setLayoutParams(params);

它在大多数设备上都运行良好,但我有一台设备,软键盘动态增长,上面有“建议”行。 那就是奇怪的事情发生的时候。

如果我的 EditText 位于屏幕顶部的某个位置,即它的矩形不与键盘相交,没有任何变化,EditText 保持原样,一切正常。 但是,如果我的 EditText 位于屏幕中间,键盘将与它重叠,它就会开始向上移动(带有动画)。

我成功地使用 SOFT_INPUT_ADJUST_PAN 来确定键盘高度(通过 getWindowVisibleDisplayFrame 调用之间的差异),所以我不能通过设置 adjustNothing 标志来禁用平移,我'我将坚持使用 adjustPan

问题是我无法理解在调整软键盘大小时(针对建议行)我的 View 位置究竟做了什么。 在我的 onGlobalLayout 中,我试图观看:

- TextView getY(),
- TextView getTranslationY(),
- TextView RelativeLayout params (topMargin, bottomMargin),
- TextView getLocationOnScreen,
- TextView getGlobalVisibleRect top & bottom,
- Activity getWindowVisibleDisplayFrame rect top & bottom.

以上都没有改变!但是无论如何,TextView 都在向上移动。 我相信在软键盘出现后,在 View 树的某个地方应用了一些偏移量。但是为什么 getLocationOnScreen 不显示这个呢?为什么 getGlobalVisibleRect 也不知道位置变化?

我想为我的 EditText 设置准确的位置,所以即使我不能阻止它向上移动(设置 adjustPan 标志的权衡),至少我需要知道它向上移动了多少,以应用反向转换

我尝试了一个非常 hacky 的解决方法:在我的 EditText beforeTextChanged() 方法中,我将 TextView 的布局 topMargin 设置为 0,以确保当建议行出现时,它不会移动我的 TextView,因为它是不再重叠。然后在 onGlobalLayout() 中恢复正确的 EditText 位置。它有效,但我不喜欢这种方式,而且它还会导致我的文本闪烁。

一些代码可以更好地理解我在做什么。

private void showKeyboard(final boolean show) {
    final InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
    if (show) {
        mEditText.requestFocus();
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                imm.showSoftInput(mEditText, 0);
            }
        }, 50);
        mVisible = true;
    } else {
        imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
        mEditText.clearFocus();
        mVisible = false;
    }
}

@Override
protected void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.native_keyboard);
    mLayout = findViewById(R.id.keyboard_layout);
    mEditText = (EditText) findViewById(R.id.keyboard_input);
    mEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
    getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
    mEditText.setInputType(mEditText.getInputType() | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE | EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS | EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE);
    mInitialFrame = getVisibleFrame();
    mPreviousFrame = mInitialFrame;
    mLayout.getViewTreeObserver().addOnGlobalLayoutListener(new android.view.ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            final int kbAssumedH = 100;
            Rect currentFrame = getVisibleFrame();
            final int dResize = (int) (mPreviousFrame.height() - currentFrame.height());
            if (mWasShown && isVisible() && dResize != 0) {
                NativeKeyboard.onKeyboardResized();
            }
            mPreviousFrame = currentFrame;

            if (isVisible() && (mInitialFrame.height() - currentFrame.height() > kbAssumedH)) {
                if (!mWasShown) {
                    NativeKeyboard.onKeyboardDidShow();
                    mWasShown = true;
                }
            } else {
                if (mWasShown) {
                    NativeKeyboard.onKeyboardDidHide();
                    mWasShown = false;
                }
            }
        }
    });     
}

这就是我如何获得不与键盘重叠的当前窗口空间:

public static synchronized android.graphics.Rect getVisibleFrame() {
    View rootView = mInstance.getWindow().getDecorView();
    android.graphics.Rect r = new android.graphics.Rect();
    rootView.getWindowVisibleDisplayFrame(r);
    return r;
}

这是我用来设置 EditText 位置的方法。 在建议行出现后,我的 EditText 在视觉上相对于我作为 Y 参数传递到这里的位置向上移动(并且移动是永久性的,即我可以用新位置调用 setRect,它也会移动)

public static synchronized void setRect(final float x, final float y, final float w, final float h) {
    if (mInstance != null) {
        Cocos2dxHelper.runOnUIThread(new Runnable() {
            @Override
            public void run() {
                    mInstance.mEditText.setX((int) x);
                    float height = mInstance.mEditText.getHeight();
                    mInstance.mEditText.setWidth((int) w);
                    float yCenter = y + h / 2;
                    float newY = yCenter - height / 2.f;
                    RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mInstance.mEditText.getLayoutParams();
                    params.topMargin = (int)newY;
                    params.width = (int)w;
                    params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
                    mInstance.mEditText.setLayoutParams(params);
            }
        });
    }
}

我尝试了 4 种不同的设备(3 部手机和 1 部平板电脑),问题仅出现在 Acer Liquid Jade Z,4.4.4 上。

提前致谢。

最佳答案

好吧,我没能捕获转变本身。 相反,在我的特定情况下可行的解决方法是这样的:

添加新的不可见对话框,用于getWindowVisibleDisplayFrame,因此当键盘显示/隐藏时您将获得所需的一切。

...并且您现在肯定希望主(可见)对话框使用 SOFT_INPUT_ADJUST_NOTHING,如果您不再需要它的 displayFrame,为什么不呢?因此,您的 View 中的任何内容都不会出现隐藏的不明显变化。

就这么简单。 希望对您有所帮助。

关于Android,如何知道我的 View 被软键盘adjustPan移动了​​多少,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37924410/

相关文章:

android - 当键盘出现在 Android 中时,EditText 超出窗口范围

android - 我的 android studio 布局管理器失去了功能

java - 软键盘关闭时执行操作

android:如何将填充添加到 FrameLayout 内的 LinearLayout

iphone - ResignFirstResponder 不会关闭键盘 (iPhone)

ios - 确定应用程序是否在 iPhone 6 键盘上以 "scaled"模式运行?

android - 如何在Android Studio中播放音频文件?

java - 发送消息时出现重复项目

android - Android 4.0 中的蓝牙智能 (4.0)/GATT 支持?

android - 无法将标题 View 添加到列表 - setAdapter 已被调用