【问题标题】:Get soft keyboard height with autocorrect part of the keyboard使用键盘的自动更正部分获取软键盘高度
【发布时间】:2019-03-03 00:02:15
【问题描述】:

我有一个使用“adjustPan”作为调整大小配置的活动,我需要在不使用“adjustResize”的情况下计算键盘高度,因为我需要将一些视图保持为全屏(这意味着它们应该保持原位,键盘应该隐藏它们),并在键盘正上方放置一个视图。我们的应用程序有一个消息按钮,我通过单击按钮打开键盘。发生这种情况时,我使用 OnGlobalLayoutListener 并使用“getWindowVisibleDisplayFrame”方法来获取键盘的高度。这是它的一些代码:

private void message()
    {
        InputMethodManager methodManager =
                (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        if (methodManager != null && !isKeyboardOpen)
        {
            methodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
            if (bottomCoordinate == 0)
            {
                RelativeLayout layout = findViewById(getFullScreenContainerId());
                layout.getViewTreeObserver().addOnGlobalLayoutListener(
                        new ViewTreeObserver.OnGlobalLayoutListener()
                        {
                            @Override
                            public void onGlobalLayout()
                            {
                                layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                                Rect r = new Rect();
                                layout.getWindowVisibleDisplayFrame(r);

                                bottomCoordinate = r.bottom - r.top;

                                translateMessageView(bottomCoordinate);
                            }
                        });
            }
            else
                translateMessageView(bottomCoordinate);
            isKeyboardOpen = true;
        }
    }

“translateMessageView”基本上将视图的 Y 坐标设置为“bottomCoordinate - view.getHeight()”。在软键盘应用程序的自动更正部分变得可见之前,这一直很好。显然,“getWindowVisibleDisplayFrame”方法似乎没有添加视图的自动更正部分,或者当软键盘的自动更正部分出现时,没有调用“onGlobalLayout”方法,并且定位的视图保持在它下方,使其半可见。我需要能够再次调整它的位置,我该怎么办?什么是正确的方法?任何建议都很有价值,谢谢。

【问题讨论】:

  • 你找到解决办法了吗?
  • @Pierre Umm,是的。在EditText 上检测到带有TextWatcher 的击键后,我在Handler.post() 调用上再次获得了可见框架,这似乎是目前为止的工作。但我在大约 6 个月后发现了这一点,这就是为什么我忘了回答自己的问题。
  • 啊,所以当文本发生变化并且额外的位弹出时,它不会改变您的隐藏视图高度,以便该部分覆盖您的输入?
  • @Pierre 不完全是,onGlobalLayout 没有被调用,但getWindowVisibleDisplayFrame(r) 的值发生了变化,所以我根据文本更改后的结果移动视图。

标签: android android-layout android-softkeyboard


【解决方案1】:

这是我在任何活动中检测键盘高度的方式,如果有的话,这也适用于缺口/切口高度。

KeyboardHeightProvider.java

import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.util.DisplayMetrics;
import android.view.DisplayCutout;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.PopupWindow;

import androidx.core.view.DisplayCutoutCompat;
import androidx.core.view.OnApplyWindowInsetsListener;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class KeyboardHeightProvider extends PopupWindow implements OnApplyWindowInsetsListener {
    private View decorView;

    private DisplayMetrics metrics;

    private LinearLayout popupView;
    private ViewTreeObserver.OnGlobalLayoutListener globalLayoutListener;

    private Rect insets = new Rect(0, 0, 0, 0);

    public KeyboardHeightProvider(Context context, WindowManager windowManager, View decorView, KeyboardHeightListener listener) {
        super(context);
        this.decorView = decorView;

        metrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(metrics);

        popupView = new LinearLayout(context);
        popupView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        globalLayoutListener = () -> {
            windowManager.getDefaultDisplay().getMetrics(metrics);

            int keyboardHeight = getKeyboardHeight();
            
            boolean screenLandscape = metrics.widthPixels > metrics.heightPixels;
            if (listener != null) {
                listener.onKeyboardHeightChanged(keyboardHeight, screenLandscape);
            }
        };

        setContentView(popupView);

        setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
        setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
        setWidth(0);
        setHeight(ViewGroup.LayoutParams.MATCH_PARENT);
        setBackgroundDrawable(new ColorDrawable(0));

        ViewCompat.setOnApplyWindowInsetsListener(popupView, this);
    }

    public void start() {
        popupView.getViewTreeObserver().addOnGlobalLayoutListener(globalLayoutListener);
        decorView.post(() -> showAtLocation(decorView, Gravity.NO_GRAVITY, 0, 0));
    }

    @Override
    public void dismiss() {
        popupView.getViewTreeObserver().removeOnGlobalLayoutListener(globalLayoutListener);
        super.dismiss();
    }

    @Override
    public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
        DisplayCutoutCompat cutoutCompat = insets.getDisplayCutout();
        if (cutoutCompat != null) {
            this.insets.set(cutoutCompat.getSafeInsetLeft(), cutoutCompat.getSafeInsetTop(), cutoutCompat.getSafeInsetRight(), cutoutCompat.getSafeInsetBottom());
        } else {
            this.insets.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
        }

        if (decorView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            WindowInsets rootWindowInsets = decorView.getRootWindowInsets();
            if (rootWindowInsets != null) {
                DisplayCutout displayCutout = rootWindowInsets.getDisplayCutout();
                if (displayCutout != null) {
                    this.insets.set(displayCutout.getSafeInsetLeft(), displayCutout.getSafeInsetTop(), displayCutout.getSafeInsetRight(), displayCutout.getSafeInsetBottom());
                }
            }
        }

        return insets;
    }

    public int getKeyboardHeight() {
        Rect rect = new Rect();
        popupView.getWindowVisibleDisplayFrame(rect);

        int keyboardHeight = metrics.heightPixels - (rect.bottom - rect.top) - (insets.bottom - insets.top);
        int resourceID = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceID > 0) {
            keyboardHeight -= context.getResources().getDimensionPixelSize(resourceID);
        }
        if (keyboardHeight < 100) {
            keyboardHeight = 0;
        }
        
        return keyboardHeight;
    }

    public interface KeyboardHeightListener {
        void onKeyboardHeightChanged(int height, boolean isLandscape);
    }
}

关于你的活动:

  1. android:windowSoftInputMode可以是任何东西,我的是stateHidden|adjustNothing

  2. 实现KeyboardHeightProvider.KeyboardHeightListener

  3. 添加一个全局变量:

     private KeyboardHeightProvider keyboardHeightProvider;
    
  4. onCreate 中添加一行:

     keyboardHeightProvider = new KeyboardHeightProvider(this, getWindowManager(), getWindow().getDecorView(), this);
    
  5. onResume 中添加一行:

     keyboardHeightProvider.start();
    
  6. onPause 中添加一行:

     keyboardHeightProvider.dismiss();
    
  7. onKeyboardHeightChanged

     @Override
     public void onKeyboardHeightChanged(int height, boolean isLandscape) {
         //This will be called anytime the keyboard height has changed.
    
         boolean keyboardOpen = height > 0;
    
         //do what you want with Keyboard Height
     }
    

【讨论】:

  • 我刚试过,然后在显示键盘时调用“onKeyboardHeightChanged”,我想在运行时获取键盘高度
  • @famfamfam 您可以添加键盘高度获取方法。将DisplayMetrics 移动到顶部作为私有局部变量。将windowManager.getDefaultDisplay().getMetrics(metrics) 移动到popupView = new... 之前。将所有行从 Rect rect =... 移动到 if (keyboardHeight &lt; 100) {...} 到返回 int keyboardHeight 的 getter 方法中。
  • 谢谢,我试过你的代码,我能问一个问题,我想像ios那样在应用启动时获得键盘高度,android版本也可以吗?
  • @famfamfam 不,必须先构建布局,然后才能测量键盘高度。您将不得不重新考虑何时以及为什么需要键盘高度。如果要设置视图高度什么的,可以在回调函数中进行
【解决方案2】:

(不是原始答案)

矩形 r = new Rect();

查看根视图 = this.getWindow().getDecorView(); // this = 活动

rootview.getWindowVisibleDisplayFrame(r);

结果是您的应用程序在屏幕上使用的空间量(即使活动没有调整大小也可以工作)。显然剩余的屏幕空间将被键盘使用(如果它可见的话)

在这里找到 id:https://github.com/freshplanet/ANE-KeyboardSize/blob/master/android/src/com/freshplanet/ane/KeyboardSize/getKeyboardY.java

您可以访问原始答案

Getting the dimensions of the soft keyboard

【讨论】:

  • 我使用几乎完全相同的方法,只有相对布局创建为“match_parent,match_parent”,因为我需要移动视图。问题是这个计算不包含软键盘的自动更正部分,我也在尝试获取它的高度。
猜你喜欢
  • 1970-01-01
  • 2014-10-06
  • 2019-04-09
  • 2014-05-26
  • 1970-01-01
  • 1970-01-01
  • 2015-05-06
  • 2013-08-28
  • 2012-12-01
相关资源
最近更新 更多