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

如何使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 14:39:02