ifdef ANDROID_

openclaw AI小龙虾攻略 2

针对OpenClaw项目的刘海屏适配,这里提供完整的解决方案:

ifdef ANDROID_-第1张图片-官方获取 | OpenClaw下载 - openclaw官网

检测刘海屏设备

// 刘海屏检测工具类
class NotchUtils {
public:
    static bool hasNotch() {
        #if defined(__ANDROID__)
        return detectAndroidNotch();
        #elif defined(__APPLE__)
        return detectiOSNotch();
        #else
        return false;
        #endif
    }
    static void getSafeAreaInsets(int& top, int& bottom, int& left, int& right) {
        // 获取安全区域
        #if defined(__ANDROID__)
        getAndroidSafeArea(top, bottom, left, right);
        #elif defined(__APPLE__)
        getiOSSafeArea(top, bottom, left, right);
        #else
        top = bottom = left = right = 0;
        #endif
    }
};

Android平台适配

1 AndroidManifest.xml配置

<!-- 全屏显示,内容延伸到刘海区域 -->
<meta-data
    android:name="android.notch_support"
    android:value="true" />
<!-- 设置窗口延伸到刘海区域 -->
<meta-data
    android:name="android.max_aspect"
    android:value="2.1" />

2 代码适配

// Android JNI接口#include <jni.h>
#include <android/log.h>
#include <android/native_window_jni.h>
extern "C" {
    JNIEXPORT jboolean JNICALL
    Java_com_yourgame_OpenClawActivity_hasDisplayCutout(JNIEnv* env, jobject thiz) {
        jclass activityClass = env->GetObjectClass(thiz);
        jmethodID getWindowMethod = env->GetMethodID(activityClass, "getWindow", "()Landroid/view/Window;");
        jobject window = env->CallObjectMethod(thiz, getWindowMethod);
        jclass windowClass = env->GetObjectClass(window);
        jmethodID getDecorViewMethod = env->GetMethodID(windowClass, "getDecorView", "()Landroid/view/View;");
        jobject decorView = env->CallObjectMethod(window, getDecorViewMethod);
        jclass viewClass = env->GetObjectClass(decorView);
        jmethodID getRootWindowInsetsMethod = env->GetMethodID(viewClass, "getRootWindowInsets", "()Landroid/view/WindowInsets;");
        jobject windowInsets = env->CallObjectMethod(decorView, getRootWindowInsetsMethod);
        if (windowInsets != nullptr) {
            jclass windowInsetsClass = env->GetObjectClass(windowInsets);
            jmethodID getDisplayCutoutMethod = env->GetMethodID(windowInsetsClass, "getDisplayCutout", "()Landroid/view/DisplayCutout;");
            jobject displayCutout = env->CallObjectMethod(windowInsets, getDisplayCutoutMethod);
            return (displayCutout != nullptr) ? JNI_TRUE : JNI_FALSE;
        }
        return JNI_FALSE;
    }
}
#endif

iOS平台适配

1 Info.plist配置

<!-- 扩展内容到刘海区域 -->
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UIStatusBarHidden</key>
<false/>
<!-- iPhone X系列适配 -->
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UISupportedInterfaceOrientations~iphone</key>
<array>
    <string>UIInterfaceOrientationPortrait</string>
    <string>UIInterfaceOrientationLandscapeLeft</string>
    <string>UIInterfaceOrientationLandscapeRight</string>
</array>

2 iOS代码适配

// iOS刘海屏检测
- (BOOL)hasNotch {
    if (@available(iOS 11.0, *)) {
        UIWindow *window = [[UIApplication sharedApplication] keyWindow];
        return window.safeAreaInsets.top > 20;
    }
    return NO;
}
- (UIEdgeInsets)safeAreaInsets {
    if (@available(iOS 11.0, *)) {
        return [[UIApplication sharedApplication] keyWindow].safeAreaInsets;
    }
    return UIEdgeInsetsZero;
}

OpenGL渲染适配

class NotchAdaptiveRenderer {
private:
    int notchTop = 0;
    int notchBottom = 0;
    int notchLeft = 0;
    int notchRight = 0;
public:
    void updateSafeArea() {
        NotchUtils::getSafeAreaInsets(notchTop, notchBottom, notchLeft, notchRight);
    }
    // 调整视口,避开刘海区域
    void adjustViewport(int screenWidth, int screenHeight) {
        int viewportX = notchLeft;
        int viewportY = notchBottom;  // OpenGL坐标原点在左下角
        int viewportWidth = screenWidth - notchLeft - notchRight;
        int viewportHeight = screenHeight - notchTop - notchBottom;
        glViewport(viewportX, viewportY, viewportWidth, viewportHeight);
    }
    // 获取游戏内容区域
    Rect getContentRect(int screenWidth, int screenHeight) {
        return Rect(
            notchLeft,
            notchBottom,
            screenWidth - notchLeft - notchRight,
            screenHeight - notchTop - notchBottom
        );
    }
    // 判断点是否在安全区域内
    bool isPointInSafeArea(int x, int y, int screenWidth, int screenHeight) {
        return (x >= notchLeft && 
                x <= screenWidth - notchRight &&
                y >= notchBottom && 
                y <= screenHeight - notchTop);
    }
};

UI布局策略

class NotchAwareUILayout {
public:
    enum LayoutMode {
        LAYOUT_FULLSCREEN,      // 全屏,内容可能被刘海遮挡
        LAYOUT_SAFE_AREA,       // 只在安全区域内显示
        LAYOUT_ADAPTIVE         // 自适应,重要内容避开刘海
    };
    struct UISafeZones {
        Rect topSafeZone;      // 顶部安全区域(通常用于状态栏)
        Rect contentSafeZone;  // 主要内容区域
        Rect bottomSafeZone;   // 底部安全区域(用于虚拟按键)
    };
    static UISafeZones calculateSafeZones(int width, int height, 
                                          int notchTop, int notchBottom, 
                                          int notchLeft, int notchRight) {
        UISafeZones zones;
        // 顶部安全区域(状态栏高度)
        zones.topSafeZone = Rect(0, height - notchTop, width, notchTop);
        // 主要内容区域(避开刘海)
        zones.contentSafeZone = Rect(
            notchLeft,
            notchBottom,
            width - notchLeft - notchRight,
            height - notchTop - notchBottom
        );
        // 底部安全区域(虚拟按键区域)
        zones.bottomSafeZone = Rect(0, 0, width, notchBottom);
        return zones;
    }
    // 放置重要UI元素到安全区域
    static void positionCriticalUI(Rect& uiRect, const UISafeZones& safeZones) {
        // 确保UI元素完全在内容安全区域内
        if (!safeZones.contentSafeZone.contains(uiRect)) {
            uiRect = uiRect.intersection(safeZones.contentSafeZone);
        }
    }
};

游戏特定适配

// OpenClaw游戏特定适配
class OpenClawNotchAdapter {
private:
    CameraController* camera;
    HUD* hud;
public:
    void adaptForNotch() {
        auto screenSize = getScreenSize();
        auto safeArea = NotchUtils::getSafeArea();
        // 1. 调整相机视角
        if (camera) {
            float aspectRatio = (screenSize.width - safeArea.left - safeArea.right) 
                              / (screenSize.height - safeArea.top - safeArea.bottom);
            camera->setAspectRatio(aspectRatio);
            // 避免重要游戏元素被刘海遮挡
            camera->setViewportMargins(
                safeArea.left, 
                safeArea.bottom, 
                safeArea.right, 
                safeArea.top
            );
        }
        // 2. 调整HUD布局
        if (hud) {
            // 分数、生命值等放在顶部安全区域下方
            hud->setPosition(HUD::POSITION_SCORE, 
                            screenSize.width / 2, 
                            screenSize.height - safeArea.top - 30);
            // 操作按钮放在底部安全区域上方
            hud->setPosition(HUD::POSITION_JUMP_BUTTON, 
                            screenSize.width - safeArea.right - 80, 
                            safeArea.bottom + 80);
            // 虚拟摇杆避开左侧刘海
            hud->setPosition(HUD::POSITION_JOYSTICK, 
                            safeArea.left + 100, 
                            safeArea.bottom + 100);
        }
        // 3. 调整游戏物品生成区域
        ItemSpawner::setSpawnBounds(
            safeArea.left + 50,
            safeArea.bottom + 50,
            screenSize.width - safeArea.right - 50,
            screenSize.height - safeArea.top - 50
        );
    }
    // 处理不同方向的刘海
    void handleOrientationChange(Orientation newOrientation) {
        updateSafeArea();
        adaptForNotch();
        // 横屏时可能需要特殊处理
        if (newOrientation == ORIENTATION_LANDSCAPE) {
            // 横屏时,刘海通常在左侧或右侧
            // 调整UI布局
            adjustHUDForLandscape();
        }
    }
};

测试方案

// 刘海屏适配测试
class NotchAdapterTest {
public:
    static void runTests() {
        testSafeAreaCalculation();
        testUIPlacement();
        testGameplayAdaptation();
    }
    static void testSafeAreaCalculation() {
        // 模拟不同刘海配置
        vector<NotchConfig> testConfigs = {
            {44, 0, 0, 0},     // iPhone X竖屏
            {0, 0, 44, 44},    // 横屏
            {30, 30, 0, 0},    // 对称刘海
            {0, 50, 0, 0},     // 只有下巴
        };
        for (auto& config : testConfigs) {
            auto safeZones = NotchAwareUILayout::calculateSafeZones(
                1080, 2340, config.top, config.bottom, config.left, config.right
            );
            assert(safeZones.contentSafeZone.width > 0);
            assert(safeZones.contentSafeZone.height > 0);
        }
    }
};

配置选项

// 刘海屏适配配置
struct NotchSettings {
    bool enableNotchAdaptation = true;
    LayoutMode layoutMode = LAYOUT_ADAPTIVE;
    // 是否允许内容延伸到刘海区域
    bool extendIntoNotch = false;
    // 刘海区域是否显示特殊效果
    bool notchAreaEffects = true;
    // 刘海区域透明度(0.0-1.0)
    float notchAreaAlpha = 0.3f;
    // 用户可调整的设置
    void saveSettings() {
        // 保存到配置文件
    }
    void loadSettings() {
        // 从配置文件加载
    }
};

最佳实践建议

分级**:

  • 关键UI元素(按钮、生命值)必须放在安全区域
  • 次要元素(装饰、背景)可以延伸到刘海区域
  • 游戏核心区域避开刘海
  1. 动态适配

    • 支持横竖屏切换
    • 支持不同刘海形状(圆形、药丸形、不规则形)
    • 支持旋转时刘海位置变化
  2. 用户体验

    • 提供适配开关
    • 保持游戏核心体验一致
    • 避免刘海区域遮挡重要信息

这个解决方案覆盖了从底层检测到上层UI适配的完整流程,可以根据OpenClaw的具体需求进行调整。

标签: ifdef ANDROID_

抱歉,评论功能暂时关闭!