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

如何监听android.support.v7.app.ActionBar的显示/隐藏状态?isShowing()无效

解决YouTube全屏模式下通过ActionBar可见性控制DialogFragment的问题

我之前在开发类似功能时也踩过这个坑,YouTube Player API确实没有直接提供ActionBar可见性的回调,而且isShowing()在这种场景下因为ActionBar的可见性逻辑和普通Dialog不同,所以不太好用。这里分享几个经过验证的方案:

方案一:监听ActionBar View的可见性变化

系统没有原生的ActionBar可见性监听器,但我们可以直接获取ActionBar的View实例,通过ViewTreeObserver监听它的布局变化来判断可见性:

// 获取AppCompat风格ActionBar对应的View(固定id为R.id.action_bar)
View actionBarView = getWindow().getDecorView().findViewById(R.id.action_bar);
if (actionBarView != null) {
    ViewTreeObserver observer = actionBarView.getViewTreeObserver();
    observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            // 检查ActionBar的可见性状态
            boolean isVisible = actionBarView.getVisibility() == View.VISIBLE;
            
            // 根据可见性控制DialogFragment,注意状态判断避免重复操作
            if (isVisible) {
                if (bottomDialogFragment == null || !bottomDialogFragment.isAdded()) {
                    bottomDialogFragment.show(getSupportFragmentManager(), "BottomDialogTag");
                }
            } else {
                if (bottomDialogFragment != null && bottomDialogFragment.isAdded()) {
                    bottomDialogFragment.dismiss();
                }
            }

            // 若只需监听一次变化,可在此移除监听器;否则建议在页面销毁时移除,防止内存泄漏
            // observer.removeOnGlobalLayoutListener(this);
        }
    });
}

方案二:结合YouTubePlayer的全屏状态回调

既然你的场景和YouTube全屏强绑定,其实可以直接利用YouTubePlayer.OnFullscreenListener间接控制DialogFragment——因为全屏切换时ActionBar的可见性通常会同步变化:

youtubePlayer.setFullscreenListener(new YouTubePlayer.OnFullscreenListener() {
    @Override
    public void onFullscreen(boolean isFullscreen) {
        ActionBar actionBar = getSupportActionBar();
        if (actionBar == null) return;

        // 全屏状态下ActionBar一般会隐藏,此时隐藏Dialog;非全屏则显示
        if (isFullscreen) {
            if (bottomDialogFragment != null && bottomDialogFragment.isAdded()) {
                bottomDialogFragment.dismiss();
            }
        } else {
            if (bottomDialogFragment == null || !bottomDialogFragment.isAdded()) {
                bottomDialogFragment.show(getSupportFragmentManager(), "BottomDialogTag");
            }
        }
    }
});

方案三:监听Window的DecorView变化

如果ActionBar是自定义布局导致无法直接获取默认View,可以监听整个Window的DecorView布局变化,通过计算可见区域推断ActionBar状态:

getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        Rect visibleFrame = new Rect();
        getWindow().getDecorView().getWindowVisibleDisplayFrame(visibleFrame);
        // 全屏状态下visibleFrame.top会变为0,非全屏时top值等于ActionBar高度
        boolean isActionBarVisible = visibleFrame.top > 0;

        // 统一逻辑控制DialogFragment显示/隐藏
        updateBottomDialogVisibility(isActionBarVisible);
    }
});

// 封装Dialog控制逻辑,避免重复代码
private void updateBottomDialogVisibility(boolean shouldShow) {
    if (shouldShow) {
        if (bottomDialogFragment == null || !bottomDialogFragment.isAdded()) {
            bottomDialogFragment.show(getSupportFragmentManager(), "BottomDialogTag");
        }
    } else {
        if (bottomDialogFragment != null && bottomDialogFragment.isAdded()) {
            bottomDialogFragment.dismiss();
        }
    }
}

关键注意事项

  • 防止内存泄漏:所有添加的ViewTreeObserver监听器,务必在Activity/Fragment的onDestroy或onDestroyView方法中移除。
  • 状态安全校验:操作DialogFragment时必须判断isAdded(),避免重复添加或销毁已回收的实例。
  • 沉浸式适配:如果使用了沉浸式全屏模式,需要结合View.SYSTEM_UI_FLAG_*相关的系统UI可见性监听,确保逻辑兼容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:31:42