如何使用WindowInsetsControllerCompat.OnControllableInsetsChangedListener?
OnControllableInsetsChangedListener 使用示例
该监听器从Android 11(API 级别 30)开始提供,可用于监听系统栏(状态栏、导航栏)、输入法等可控制窗口元素的可见性变动,刚好适配监听系统UI变化切换菜单UI的需求
1. 核心实现流程
- 获取当前页面
WindowInsetsController实例 - 实现监听器接口,在回调中通过位掩码判断目标系统UI的可见状态,执行菜单UI的切换逻辑
- 注册监听器到
WindowInsetsController - 页面销毁时取消注册,避免内存泄漏
2. 完整代码示例
Java 版本
import android.os.Build; import android.os.Bundle; import android.view.WindowInsets; import android.view.WindowInsetsController; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { private WindowInsetsController.OnControllableInsetsChangedListener insetsListener; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { WindowInsetsController insetsController = getWindow().getInsetsController(); if (insetsController != null) { insetsListener = (controller, typeMask) -> { // 位运算判断对应系统UI是否可见 boolean isStatusBarVisible = (typeMask & WindowInsets.Type.statusBars()) != 0; boolean isNavBarVisible = (typeMask & WindowInsets.Type.navigationBars()) != 0; // 替换为你自己的菜单UI切换逻辑 if (isStatusBarVisible || isNavBarVisible) { showCustomMenu(); } else { hideCustomMenu(); } }; // 注册监听器,指定回调执行在主线程 insetsController.addOnControllableInsetsChangedListener(Runnable::run, insetsListener); } } } private void showCustomMenu() { // 自定义菜单展示逻辑 } private void hideCustomMenu() { // 自定义菜单隐藏逻辑 } @Override protected void onDestroy() { super.onDestroy(); // 取消注册避免内存泄漏 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { WindowInsetsController insetsController = getWindow().getInsetsController(); if (insetsController != null && insetsListener != null) { insetsController.removeOnControllableInsetsChangedListener(insetsListener); } } } }
Kotlin 版本
import android.os.Build import android.os.Bundle import android.view.WindowInsets import android.view.WindowInsetsController import androidx.appcompat.app.AppCompatActivity class MainActivity : AppCompatActivity() { private var insetsListener: WindowInsetsController.OnControllableInsetsChangedListener? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { window.insetsController?.let { controller -> insetsListener = WindowInsetsController.OnControllableInsetsChangedListener { _, typeMask -> val isStatusBarVisible = typeMask and WindowInsets.Type.statusBars() != 0 val isNavBarVisible = typeMask and WindowInsets.Type.navigationBars() != 0 // 替换为你自己的菜单UI切换逻辑 if (isStatusBarVisible || isNavBarVisible) { showCustomMenu() } else { hideCustomMenu() } } controller.addOnControllableInsetsChangedListener(mainExecutor, insetsListener!!) } } } private fun showCustomMenu() { // 自定义菜单展示逻辑 } private fun hideCustomMenu() { // 自定义菜单隐藏逻辑 } override fun onDestroy() { super.onDestroy() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { window.insetsController?.removeOnControllableInsetsChangedListener(insetsListener ?: return) } } }
3. 注意事项
- 该API仅支持Android 11(API 30)及以上版本,低于30的系统需使用
View.OnSystemUiVisibilityChangeListener替代实现 - 可根据需求监听其他窗口元素的可见性,比如把
WindowInsets.Type.statusBars()替换为WindowInsets.Type.ime()即可监听输入法的显隐 - 回调返回的
typeMask是位掩码类型,必须通过按位与的方式判断对应元素是否可见
内容的提问来源于stack exchange,提问作者Kichiemon
相关产品推荐
相关产品推荐

