You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

libGDX 与 Android 15 的边缘到边缘(edge-to-edge)强制规范

libGDX 与 Android 15 的边缘到边缘(edge-to-edge)强制规范

嘿,刚好我之前踩过这个坑,给你捋捋怎么在libGDX里搞定状态栏、导航栏和刘海的尺寸位置适配,完美符合Google的边缘到-edge要求~

核心思路:借助Android原生代码拿系统UI信息

libGDX是跨平台框架,本身没直接提供获取Android系统UI的API,所以得在Android端的AndroidLauncher里通过原生代码拿到这些数据,再传递给libGDX的游戏逻辑里用。

1. 先开启边缘到-edge模式

首先得在AndroidLauncher的onCreate里打开这个模式,让应用可以延伸到系统UI的区域:

getWindow().setDecorFitsSystemWindows(false);

2. 获取状态栏的高度

状态栏高度可以通过Android的资源ID获取,兼容大部分旧版本:

int statusBarHeight = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
    statusBarHeight = getResources().getDimensionPixelSize(resourceId);
}

3. 获取导航栏的尺寸与位置

导航栏可能在底部或侧边(比如平板),所以用WindowInsets获取上下左右的内边距更准确(Android 10+推荐),旧版本可以 fallback 到资源ID获取高度:

int navBarLeft = 0, navBarTop = 0, navBarRight = 0, navBarBottom = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    WindowInsets insets = getWindow().getDecorView().getRootWindowInsets();
    if (insets != null) {
        Insets navInsets = insets.getInsets(WindowInsets.Type.navigationBars());
        navBarLeft = navInsets.left;
        navBarTop = navInsets.top;
        navBarRight = navInsets.right;
        navBarBottom = navInsets.bottom;
    }
} else {
    int navBarId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
    if (navBarId > 0) {
        navBarBottom = getResources().getDimensionPixelSize(navBarId);
    }
}

4. 处理刘海(Cutouts)区域

首先要在AndroidManifest.xml里设置允许应用延伸到刘海区域:

<meta-data
    android:name="android.window.layoutInDisplayCutoutMode"
    android:value="shortEdges" />

然后在AndroidLauncher里获取刘海的安全区域和具体矩形位置:

int safeLeft = 0, safeTop = 0, safeRight = 0, safeBottom = 0;
List<Rect> cutoutRects = new ArrayList<>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    DisplayCutout cutout = getWindow().getDecorView().getRootWindowInsets().getDisplayCutout();
    if (cutout != null) {
        safeLeft = cutout.getSafeInsetLeft();
        safeTop = cutout.getSafeInsetTop();
        safeRight = cutout.getSafeInsetRight();
        safeBottom = cutout.getSafeInsetBottom();
        cutoutRects = cutout.getBoundingRects(); // 所有刘海的矩形区域
    }
}

5. 把数据传递给libGDX游戏

把上面拿到的所有参数传给你的libGDX游戏实例,比如:

MyGame game = new MyGame(statusBarHeight, navBarLeft, navBarTop, navBarRight, navBarBottom, safeLeft, safeTop, safeRight, safeBottom, cutoutRects);
initialize(game, config);

这里要注意:libGDX的坐标原点是左下角,而Android是左上角,所以转换的时候要做调整,比如状态栏的底部在libGDX里的Y坐标是Gdx.graphics.getHeight() - statusBarHeight,安全区域的顶部Y坐标是Gdx.graphics.getHeight() - safeTop。

6. 监听屏幕旋转,动态更新数据

屏幕旋转后,系统UI的位置尺寸会变化,所以要在AndroidLauncher里重写onConfigurationChanged方法,重新获取数据并通知游戏更新:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    // 重复上面的获取逻辑,拿到新的参数
    // ...
    // 通知游戏更新,要确保在GL线程执行
    ((MyGame) getApplicationListener()).updateSystemUIInsets(/* 新参数 */);
}

然后在MyGame里写对应的更新方法:

public void updateSystemUIInsets(/* 所有参数 */) {
    Gdx.app.post(() -> {
        // 更新类内的变量
        // 触发UI重新布局
    });
}

最后小提示

你可以用这些数据调整UI布局:比如把按钮、文本等重要内容放在安全区域内,背景可以延伸到系统UI和刘海区域,既满足edge-to-edge的要求,又不会让内容被遮挡。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 08:14:31