在Android中有没有一种方法可以获取设备虚拟键盘的高度?

64

在Android中,是否有一种方法可以在运行时获取设备上显示的虚拟键盘的高度?实际上,我想在键盘上方显示一个文本框。


在Android中获取虚拟键盘的高度。 - Oli
2
但是这个问题是2年前提出的,现在可能已经有一些解决方案了。 - Zeeshan Mirza
16个回答

1

我的解决方案是结合了上述所有解决方案。这个方法也有些取巧,但解决了问题(至少对我来说是这样的)。

  1. 我在屏幕底部添加了透明背景的临时视图。
  2. 我在清单文件中的活动标签中添加了android:windowSoftInputMode="adjustResize"标志,就像@bill建议的那样。
  3. 现在主要部分在于onGlobalLayout()。在那里,我计算临时视图y轴和根视图高度之间的差异

    final View view = findViewById(R.id.base);
    
    view.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    
        @Override
        public void onGlobalLayout() {
    
            int rootViewHeight = view.getRootView().getHeight();
            View tv = findViewById(R.id.temp_view);
            int location[] = new int[2];
            tv.getLocationOnScreen(location);
            int height = (int) (location[1] + tv.getMeasuredHeight());
            deff = rootViewHeight - height;
            // deff是软键盘的高度
    
        }
    });
    

但是,为了解决@zeeshan0026的问题,只需要在清单文件中添加一个标志 android:windowSoftInputMode="adjustResize" 就足够了。


4
使用 android:windowSoftInputMode="adjustNothing" 可以获取键盘高度吗? - VijayRaj
1
如果我们使用adjustNothing标志,那么当键盘打开时视图将不会重新渲染,因此显然不应调用onGlobalLayout,我们将无法获得大小的变化。虽然我自己没有尝试过,但这就是预期的结果。 - Gem

1
我终于找到了获取软键盘高度的解决方案。我不能说这适用于所有设备,但我在一些真实设备和模拟器上尝试过,它有效。我尝试过Android API 16至29的设备。这有点棘手。以下是我的分析。
首先,我尝试使用getHeightDifference()函数计算软/虚拟键盘顶部可见框架的高度与屏幕高度之间的差值。我发现,在第一次创建布局时,在EditText聚焦并打开键盘之前,高度差将取决于Android系统导航栏是否显示在设备屏幕内。因此,如果导航栏在屏幕外,则heightDifference的值为0;如果导航栏在屏幕内,则大于0。我使用一个Integer对象的systemNavigationBarHeight变量(而不是使用原始的int数据)来保存该高度差的第一个值,并进行一次初始化,我假设这是Nav Bar的高度。
在下一个代码块中,我检查下一个高度差是否大于Android系统中实际导航栏的高度(如果Android系统中没有导航栏,则默认为100),然后再次减去systemNavigationBarHeight的值以获取软键盘的实际高度。希望这对正在寻找答案的人有所帮助。
public class MyActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        rootView.getViewTreeObserver()
                .addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
                    private Integer systemNavigationBarHeight = null;
                        
                    @Override
                    public void onGlobalLayout() {
                        int heightDifference = getHeightDifference();
                        if (heightDifference > 0) {
                            if (systemNavigationBarHeight == null) {
                                /* Get layout height when the layout was created at first time */
                                systemNavigationBarHeight = heightDifference;
                            }
                        } else {
                            systemNavigationBarHeight = 0;
                        }

                        if (heightDifference > getDefaultNavigationBarHeight()) {
                            /* Keyboard opened */
                            int keyBoardHeight = heightDifference - systemNavigationBarHeight;
                        } else {
                            /* Keyboard closed */
                        }
                    }
        }
    }
    
    private int getHeightDifference() {
        Point screenSize = new Point();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            getWindowManager().getDefaultDisplay().getRealSize(screenSize);
        } else {
            getWindowManager().getDefaultDisplay().getSize(screenSize);
        }

        Rect rect = new Rect();
        rootView.getWindowVisibleDisplayFrame(rect);
        return screenSize.y - rect.bottom;
    }
    
    private int getDefaultNavigationBarHeight() {
        int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
        if (resourceId > 0) {
            return getResources().getDimensionPixelSize(resourceId);
        }
        return 100;
    }
}

我使用了你的代码来解决React Native中的问题 https://github.com/troZee/react-native-keyboard-dimens。非常感谢你分享你的想法。 - Piotr Badura
@PiotrBadura 很高兴为您服务 :) - damai007

0

2023解决方案

如果您使用androidx.compose.foundation,您可以轻松获取IME可见性和高度(底部),如下所示:

val imeVisible = WindowInsets.isImeVisible
val bottom = WindowInsets.ime.getBottom(LocalDensity.current)

设置步骤,您可以 观看此视频 或者:

  1. 在你的活动的 onCreate 方法中:

     window.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
     WindowCompat.setDecorFitsSystemWindows(window, false)
    
  2. AndroidManifest.xml

    <application ... android:windowSoftInputMode="adjustResize">

  3. Themes.xml

    <item name="android:statusBarColor">@android:color/transparent</item>

    <item name="android:navigationBarColor">@android:color/transparent</item>


0

不用再找了! 我已经寻找这个问题的解决方案很长时间了。在尝试了SOF上所有建议的技巧数天后,我终于找到了完美的解决方案。

这个GitHub项目以最好的方式演示了它: https://github.com/siebeprojects/samples-keyboardheight

玩得开心!


2
嗨,看这边!伙计,我们尝试了同样的解决方案,由于这个“不要再看”的原因,我们的应用程序出现了20多个错误。所以你绝对需要更加努力地去寻找解决方案,而不是停止搜索:D - AndroidEngineX

0
对于API >= 30。
@RequiresApi(Build.VERSION_CODES.R)
private fun getKeyboardHeight(view: View): Int {
    return view.rootWindowInsets.getInsets(WindowInsetsCompat.Type.ime()).bottom -
            getNavBarHeight(view)
}

@RequiresApi(Build.VERSION_CODES.R)
private fun getNavBarHeight(view: View): Int {
    return view.rootWindowInsets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom
}

@RequiresApi(Build.VERSION_CODES.R)
private fun isKeyboardVisible(insets: WindowInsets): Boolean {
    return insets.isVisible(WindowInsetsCompat.Type.ime())
}

另请参阅https://www.kodeco.com/18393648-window-insets-and-keyboard-animations-tutorial-for-android-11

-1
我发现对我非常好的一个解决方案是,存储一个全局的bottom值,然后添加一个TreeView Observer并将新的底部值与存储的值进行比较。使用android:windowSoftInputMode="adjustResize"
private var bottom: Int = 0

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    
    val rect = Rect()
    this.window.decorView.getWindowVisibleDisplayFrame(rect)
    this.bottom = rect.bottom

    this.window.decorView.viewTreeObserver.addOnGlobalLayoutListener {
        
        val newRect = Rect()
        this.window.decorView.getWindowVisibleDisplayFrame(newRect)
        
        // the answer
        val keyboardHeight = this.bottom - newRect.bottom

        // also
        if (newRect.bottom < this.bottom) {
            //keyboard is open
            
        } else {
            //keyboard is hide
            
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接