当前位置: 首页 > news >正文

「Unity3D」使用C#获取Android虚拟键盘的高度

原理是:利用getWindowVisibleDisplayFrame方法,获取Android窗口可见区域的Rect,这个Rect剔除了状态栏与导航栏,并且在有虚拟键盘遮挡的时候,会剔除这个遮挡区域。

接着,UnitysafeArea也剔除了状态栏与导航栏,且不会剔除虚拟键盘遮挡——那么,safeArea.height - getWindowVisibleDisplayFrame.height,就是虚拟键盘的高度。

public static float GetKeyboardHeight()
{
    #if UNITY_ANDROID && !UNITY_EDITOR
    using var unityPlayerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    using var activity         = unityPlayerClass.GetStatic<AndroidJavaObject>("currentActivity");
    using var window           = activity.Call<AndroidJavaObject>("getWindow");
    using var decorView        = window.Call<AndroidJavaObject>("getDecorView");     
    using var rect             = new AndroidJavaObject("android.graphics.Rect");

    decorView.Call("getWindowVisibleDisplayFrame", rect);

    return Screen.safeArea.height - rect.Call<int>("height");
    #else
    return TouchScreenKeyboard.area.height;
    #endif
}

在实际中的问题是,虚拟键盘有动画,getWindowVisibleDisplayFrame获取有延迟,所以需要不断调用GetKeyboardHeight(),大概20帧左右,才能获取虚拟键盘高度的变化——于是AndroidJava对象,就会反复创建与释放。

一个解决方案是,使用协程,即只在高度变化时才返回(利用IEnumeratorCurrent,也可以用回调函数),如下:

/// <summary>
/// Waits until the keyboard height is different from the [oldHeight], and return the new height with [IEnumerator.Current].
/// By using Coroutine to reduce the call and dispose of Java objects. 
/// </summary>
public static IEnumerator GetKeyboardHeight(float oldHeight)
{
    #if UNITY_ANDROID && !UNITY_EDITOR
    using var unityPlayerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    using var activity         = unityPlayerClass.GetStatic<AndroidJavaObject>("currentActivity");
    using var window           = activity.Call<AndroidJavaObject>("getWindow");
    using var decorView        = window.Call<AndroidJavaObject>("getDecorView");     
    using var rect             = new AndroidJavaObject("android.graphics.Rect");

    while (true)
    {
        decorView.Call("getWindowVisibleDisplayFrame", rect);
        var keyboardHeight = Screen.safeArea.height - rect.Call<int>("height");

        if (oldHeight != keyboardHeight)
        {
            yield return keyboardHeight;
            yield break;
        }

        yield return null;
    }
    #else
    yield return TouchScreenKeyboard.area.height;
    #endif
}

再给出一个,可以响应虚拟键盘不同状态的版本, 而safeArea.height也可以放到循环检测外面。

/// <summary>
/// Waits until the keyboard height is different from the [oldHeight], and return the new height with [IEnumerator.Current].
/// If [IEnumerator.Current] is 0.0f, the keyboard needs to be closed.
/// By using Coroutine to reduce the call and dispose of Java objects. 
/// </summary>
public static IEnumerator GetKeyboardHeight(float oldHeight, TouchScreenKeyboard keyboard)
{
    #if UNITY_ANDROID //&& !UNITY_EDITOR
    using var unityPlayerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    using var activity         = unityPlayerClass.GetStatic<AndroidJavaObject>("currentActivity");
    using var window           = activity.Call<AndroidJavaObject>("getWindow");
    using var decorView        = window.Call<AndroidJavaObject>("getDecorView");     
    using var rect             = new AndroidJavaObject("android.graphics.Rect");
          var safeAreaHeight   = Screen.safeArea.height;

    while (true)
    {
        switch (keyboard.status)
        {
            case TouchScreenKeyboard.Status.Visible:
                decorView.Call("getWindowVisibleDisplayFrame", rect);
                var keyboardHeight = safeAreaHeight - rect.Call<int>("height");

                if (oldHeight != keyboardHeight)
                {
                    yield return keyboardHeight;
                    yield break;
                }                    
                break;

            case TouchScreenKeyboard.Status.Done:
            case TouchScreenKeyboard.Status.Canceled:
            case TouchScreenKeyboard.Status.LostFocus:
                yield return 0.0f;
                yield break;
        }

        yield return null;
    }
    #else
    yield return TouchScreenKeyboard.area.height;
    #endif
}

http://www.dtcms.com/a/89385.html

相关文章:

  • hackmyvm-immortal
  • PCL 1.12.0 释放std::free(ptr)问题解决
  • 3.25-2request库
  • Sublime全局搜索快捷键Ctrl+Shift+F不能使用解决
  • react中 useEffect和useLayoutEffect的区别
  • ANYmal Parkour: Learning Agile Navigation for Quadrupedal Robots
  • 使用go实现下载导入Excel模板
  • 2025年- G29-Lc103-3. 最长无重复字符的子字符串--java版
  • PHP接口开发:从基础到高级的全面指南
  • 算法题(107):function
  • Windows 10/11 使用 VSCode + SSH 免密远程连接 Ubuntu 服务器(指定端口)
  • matlab使用fmincon开加速
  • 光电效应及普朗克常数的测定数据处理 Python实现
  • 时隔多年,终于给它换了皮肤,并正式起了名字
  • 洛谷: P1443 马的遍历
  • OpenHarmony 入门——ArkUI 跨页面数据同步和应用全局单例的UI状态存储AppStorage 小结(三)
  • QML控件 - Slider
  • python脚本处理excel文件
  • 如何选择?Postman vs JMeter 对比介绍
  • zynq7020 最小ps环境速通
  • 开源大模型使用总结
  • Unity选择框(魔兽争霸3)
  • 文生图语义识别插件使用(controlnet)
  • STM32F103_LL库+寄存器学习笔记01 - 梳理CubeMX生成的LL库最小的裸机系统框架
  • immortalwrt一键istoreOS风格化
  • Unity射击游戏手榴弹笔记
  • 广告推荐算法 - 学习笔记
  • AL11和SM69 文件服务器中创建文件夹
  • 二叉树练习
  • 垃圾短信分类