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

Pixel 3设备GLSurfaceView竖屏圆角异常及全圆角实现咨询

解决Pixel 3竖屏GLSurfaceView仅顶部圆角的问题

我之前调试Pixel系列设备的GLSurfaceView圆角适配时,刚好碰到过一模一样的情况——系统默认只给顶部状态栏对应的区域应用了圆角裁剪,但底部导航栏对应的GLSurfaceView区域没被处理。下面分享两种经过验证的解决方案,都是热门3D游戏常用的思路:

方案1:利用Android View的Outline裁剪(简单易实现)

SurfaceView(包括GLSurfaceView)的Surface默认独立于Window的Surface,所以普通的setClipToOutline(true)可能不生效,需要先让GLSurfaceView的Surface和Window的Insets对齐:

  1. 开启GLSurfaceView的窗口Insets适配
    在你的GLSurfaceView初始化代码里添加:

    glSurfaceView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
    glSurfaceView.setOnApplyWindowInsetsListener((v, insets) -> {
        // 获取系统提供的圆角半径(用Insets更适配不同设备)
        WindowInsetsCompat insetsCompat = WindowInsetsCompat.toWindowInsetsCompat(insets);
        DisplayCutoutCompat cutout = insetsCompat.getDisplayCutout();
        if (cutout != null) {
            // Pixel3上下圆角半径一致,取底部对应的值
            float cornerRadius = cutout.getCornerRadii()[2];
            // 创建完整圆角的Outline
            Outline outline = new Outline();
            outline.setRoundRect(0, 0, v.getWidth(), v.getHeight(), cornerRadius);
            v.setOutline(outline);
            v.setClipToOutline(true);
        }
        return insets.consumeSystemWindowInsets();
    });
    

    核心是通过DisplayCutout获取系统原生圆角半径,给GLSurfaceView设置覆盖四边的圆角Outline,再开启裁剪。

  2. 注意事项

    • 确保Activity是全屏模式(或布局延伸到状态栏、导航栏下方),否则无法获取正确的Insets信息
    • 部分Android版本需要在布局文件的GLSurfaceView标签中添加android:clipToOutline="true"

方案2:OpenGL渲染层手动绘制圆角遮罩(游戏常用,更灵活)

如果方案1在某些场景下不生效(比如OpenGL渲染内容需要突破View裁剪限制),可以在OpenGL渲染流程中手动添加圆角遮罩层:

  1. 准备圆角遮罩的Shader
    创建片段Shader实现圆角裁剪逻辑:

    precision mediump float;
    varying vec2 v_texCoord;
    uniform vec2 u_resolution;
    uniform float u_radius;
    
    void main() {
        vec2 pos = gl_FragCoord.xy / u_resolution;
        vec2 center = vec2(0.5, 0.5);
        vec2 dist = abs(pos - center);
        float circleDist = length(dist);
        // 计算圆角区域的透明度,实现遮罩效果
        float alpha = smoothstep(u_radius / u_resolution.x, (u_radius + 1.0) / u_resolution.x, circleDist);
        gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0 - alpha);
    }
    

    这个Shader会在屏幕四个角绘制透明圆角区域,遮挡GLSurfaceView的角落。

  2. 在渲染流程中添加遮罩绘制
    在onDrawFrame方法的最后,绘制覆盖全屏的矩形并应用遮罩Shader:

    // 假设已加载并链接好遮罩Shader程序
    int maskProgram = ...;
    glUseProgram(maskProgram);
    // 传入屏幕分辨率和圆角半径(Pixel3的圆角半径约为18dp,转成像素值)
    glUniform2f(glGetUniformLocation(maskProgram, "u_resolution"), screenWidth, screenHeight);
    glUniform1f(glGetUniformLocation(maskProgram, "u_radius"), dpToPx(18));
    // 绘制全屏矩形
    glBindBuffer(GL_ARRAY_BUFFER, fullScreenVbo);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glDisableVertexAttribArray(0);
    

    这种方式完全由OpenGL控制,不受View层级限制,是热门3D游戏的主流方案。

为什么热门游戏能实现全圆角?

大部分热门游戏会选择方案2,因为他们的渲染逻辑完全在OpenGL层,通过遮罩可以精准控制圆角显示,同时避免View层级的兼容性问题;部分游戏也会结合方案1,利用系统Insets信息动态适配不同设备的圆角半径。

内容的提问来源于stack exchange,提问作者Xavier

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:51:46