Unity适配 安卓15+三键导航模式下的 底部UI被遮挡

在发布android15以上的apk,如果手机采用的经典导航键,那么底部的按钮将会被安全区域遮挡。

解决这个问题,有两种思路。

1.打开全屏模式

cs 复制代码
private void FullScreen()
{
    // 强制设置全屏
    Screen.fullScreen = true;
    // 使用沉浸模式,隐藏底部的虚拟按键
    Screen.fullScreenMode = FullScreenMode.ExclusiveFullScreen;
}

全屏下,导航栏会默认消失,但是你从底部下往上滑动的时候,导航栏会出现,一会后会自动消失

2.获取安全区域的高度,让UI的位置+安全区域的高度

cs 复制代码
    private RectTransform rt;
    private Canvas canvas;

    private void ApplySafeOffset()
    {

        rt = GetComponent<RectTransform>();
        canvas = GetComponentInParent<Canvas>();
        if (rt == null || canvas == null) return;

        float bottomPixelHeight = 0;

        // 首先尝试原生接口 
        if (Application.platform == RuntimePlatform.Android)
        {
            bottomPixelHeight = GetAndroidBottomInset();
            if (bottomPixelHeight > 0)
                Debug.Log($"[SafeAreaAdapter] 从 Android 底层获取到避让高度: {bottomPixelHeight}");
        }
        else
            return;

     
        if (bottomPixelHeight > 0)
        {
            float scaleFactor = canvas.scaleFactor;
            float offsetInCanvas = bottomPixelHeight / scaleFactor;

            Vector2 newPos = rt.anchoredPosition;
            newPos.y = offsetInCanvas; // 直接设置为偏移量,避免重复累加
            rt.anchoredPosition = newPos;
            Debug.Log($"[SafeAreaAdapter] 适配成功: {offsetInCanvas} Canvas单位");
        }
        else
        {
            Debug.Log("[SafeAreaAdapter] 所有检测均返回0,可能是全屏手势模式。");
        }
    }

    // 调用 Android 原生 API 获取真正的底部高度
    private float GetAndroidBottomInset()
    {
        try
        {
            using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
            using (var activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
            using (var window = activity.Call<AndroidJavaObject>("getWindow"))
            using (var decorView = window.Call<AndroidJavaObject>("getDecorView"))
            using (var rootInsets = decorView.Call<AndroidJavaObject>("getRootWindowInsets"))
            {
                if (rootInsets != null)
                {
                    // 获取系统窗口插入高度 (包括导航栏)
                    return rootInsets.Call<int>("getSystemWindowInsetBottom");
                }
            }
        }
        catch (System.Exception e)
        {
            Debug.LogError("[SafeAreaAdapter] 获取原生 Insets 出错: " + e.Message);
        }
        return 0;
    }

这里增加一个判断,要大于35的才能去抬高,因为在android15之前,是不用抬起的,这里不加判断设置android版本的话,只要有安全区域就会抬起,是有问题

复制代码
    public int GetAndroidSDKVersion()
    {
#if UNITY_ANDROID && !UNITY_EDITOR
    using (var version = new AndroidJavaClass("android.os.Build$VERSION"))
    {
        // Android 15 对应的 SDK_INT 是 35
        return version.GetStatic<int>("SDK_INT");
    }
#endif
        return -1;
    }
相关推荐
QING6181 小时前
Android Gradle Plugin 9.0 升级指南:告别十年技术债,你准备好了吗?
android·kotlin·gradle
Ehtan_Zheng1 小时前
内存泄漏检测:发现隐藏泄漏的工具
android
拭心1 小时前
Android 17 来了!新特性介绍与适配建议
android
Kapaseker1 小时前
一杯美式理解 Inner Class
android·kotlin
三少爷的鞋2 小时前
为什么 Google 不再推荐 SharedPreferences?答案其实只有一个:锁
android
JMchen1232 小时前
企业级图表组件库完整实现
android·java·经验分享·笔记·canvas·android-studio
草明11 小时前
android 蓝牙连接-兼容旧版本
android
鹏多多.11 小时前
Flutter使用screenshot进行截屏和截长图以及分享保存的全流程指南
android·前端·flutter·ios·前端框架
Flywith2414 小时前
【每日一技】Warp Workflow 使用示例
android·前端
冬奇Lab14 小时前
JobScheduler与WorkManager:任务调度机制
android·源码阅读