Android游戏开发中隐藏导航栏问题求助
Android游戏隐藏导航栏问题解决指南
问题背景
开发Android游戏时需要隐藏主界面导航栏,尝试多种方法无效:
- 使用
getWindow().setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN)仅隐藏标题栏,导航栏仍显示 - 调用
setSystemUiVisibility设置沉浸式后,Honor 9X出现图形错位,Samsung S10因线程相关问题崩溃
项目结构:
- 布局文件
juego.xml用FrameLayout包含自定义ViewVistaJuego VistaJuego内部定义ThreadJuego循环执行物理更新Juego类(继承AppCompatActivity)负责加载视图
解决方案
1. 适配全版本的系统UI隐藏实现
在Juego类中完善全屏逻辑,覆盖Android 11+和旧版本,同时监听窗口焦点防止导航栏复现:
public class Juego extends AppCompatActivity { VistaJuego vistaJuego; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); hideSystemUI(); setContentView(R.layout.juego); vistaJuego = findViewById(R.id.VistaJuego); } private void hideSystemUI() { Window window = getWindow(); // 隐藏标题栏 supportRequestWindowFeature(Window.FEATURE_NO_TITLE); window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // 适配Android 11+及旧版本的导航栏隐藏 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { WindowInsetsController insetsController = window.getInsetsController(); if (insetsController != null) { insetsController.hide(WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars()); insetsController.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE); } } else { window.getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE ); } } // 窗口重新获得焦点时,重新隐藏系统UI @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { hideSystemUI(); } } @Override protected void onDestroy() { super.onDestroy(); if (vistaJuego != null) { vistaJuego.stopThread(); } } }
2. 修复线程启动导致的崩溃问题
原VistaJuego中线程无退出机制且可能重复启动,修改后添加运行状态控制和休眠逻辑:
public class VistaJuego extends View { private ThreadJuego thread; private boolean isRunning = false; public VistaJuego(Context context, AttributeSet attrs) { super(context, attrs); // 初始化图形资源 } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // 确保线程仅启动一次 if (!isRunning) { thread = new ThreadJuego(); isRunning = true; thread.start(); } } @Override protected synchronized void onDraw(Canvas canvas) { super.onDraw(canvas); // 绘制游戏元素逻辑 } protected synchronized void actualizaFisica() { // 游戏物理更新逻辑 } // 停止线程的方法,在Activity销毁时调用 public void stopThread() { isRunning = false; if (thread != null) { try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } thread = null; } } class ThreadJuego extends Thread { @Override public void run() { while (isRunning) { actualizaFisica(); // 添加休眠,控制帧率并降低CPU占用 try { Thread.sleep(16); // 对应约60帧/秒 } catch (InterruptedException e) { e.printStackTrace(); } } } } }
3. 调整布局适配全屏
修改juego.xml,添加fitsSystemWindows="false"确保布局填充整个屏幕:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="false"> <com.richard_tfg.tankgame.VistaJuego android:id="@+id/VistaJuego" android:layout_width="match_parent" android:layout_height="match_parent" android:focusable="true" android:background="@drawable/mapa_batalla2" android:fitsSystemWindows="false"/> </FrameLayout>
关键要点
LAYOUT_FULLSCREEN和LAYOUT_HIDE_NAVIGATION确保布局延伸至全屏,解决图形错位问题IMMERSIVE_STICKY实现导航栏滑出后自动隐藏,不干扰游戏操作- 线程添加
isRunning标志避免重复启动,休眠逻辑降低CPU占用 onWindowFocusChanged监听确保窗口重新聚焦时保持全屏状态
内容的提问来源于stack exchange,提问作者Richman19
相关产品推荐
相关产品推荐

