ActionBar 覆盖来自 YouTube 播放器的 YouTubePlayerSupportFragment API

ActionBar overlaying YouTubePlayerSupportFragment from YouTube Player API

我有一个 activity 扩展 AppCompatActivity,使用扩展 Theme.AppCompat.Light.DarkActionBar 的主题。 此 activity 的视图是 LinearLayoutVERTICAL 方向,包含以下视图:

  1. 一个 FrameLayout 包含一个 YouTubePlayerSupportFragment。请注意,我在初始化成功时对获得的 YouTubePlayer 调用以下方法:

    setPlayerStyle(PlayerStyle.CHROMELESS)
    addFullscreenControlFlag(YouTubePlayer.FULLSCREEN_FLAG_CUSTOM_LAYOUT)
    

    我还在播放器视图上设置了一个 onClickListener,应该根据需要隐藏和显示 ActionBar

  2. 包含视频详细信息和内容的另一个视图

  3. 一些底视图

请注意 activity 调用 supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR_OVERLAY) 并且 LinearLayout 的顶部填充为 android.support.v7.appcompat.R.attr.actionBarSize

AndroidManifest.xml 中,activity 设置了 android:configChanges="orientation|screenSize"

在 activity 的 onConfigurationChanged 方法中,我正在检查屏幕方向。如果是横向,我就"going fullscreen",如果是纵向,我就回到正常布局。

"going fullscreen",我的意思是:

  1. 将视图 n°2 和视图 n°3 visibility 设置为 View.GONE
  2. 将 activity 的 supportActionBar 背景颜色设置为透明颜色,例如 0x55000000
  3. 正在将 getWindow().getDecorView().systemUiVisibility 设置为 View.SYSTEM_UI_FLAG_FULLSCREEN
  4. 更改视图 n°1 LayoutParams,同时将 widthheight 设置为 MATCH_PARENT
  5. YouTubePlayer
  6. 上调用 setFullscreen(true)

现在,当我在我的应用程序中时,一切都在纵向模式下工作:视频播放,播放器正确放置在 ActionBar 下方。当进入横向模式时,它继续按预期工作:除了播放器(甚至 ActionBar ),一切都消失了。然后我点击现在全屏的 YouTube 播放器。

预期的结果是 ActionBar 出现,不会中断播放。

实际结果是系统状态栏和ActionBar都出现了,播放中断,报如下错误:

YouTube video playback stopped due to unauthorized overlay on top of player. The YouTubePlayerView is obscured by android.support.v7.widget.ActionBarContainer{43744840 V.ED.... ........ 0,50-1280,162 #7f0d005b app:id/action_bar_container}. The view is inside the YouTubePlayerView, with the distance in px between each edge of the obscuring view and the YouTubePlayerView being: left: 0, top: 50, right: 0, bottom: 558..

YouTubePlayer 应该让 ActionBar 覆盖它,如 Overlay ActionBar Demo found in the Sample Applications 所示。那么这里的问题是什么?我以为它只是检查覆盖它的视图是否是一个 ActionBar,所以我不明白这个确切的错误是怎么可能的!

好的,因为确实不支持 Android YouTube 播放器 API,我将回答您实际上必须如何操作才能正常工作。

首先,放弃使用 ActionBar 的想法。这是一个旧的 API,里面有控件很难看,处理起来很痛苦,而且 甚至不起作用 如果你不使用由Google。这个答案的其余部分将解释如何在 YouTube 播放器上添加控件的工作方法,但是如果你真的想使用 ActionBar,你不会在这里找到答案(据我所知也没有其他地方)。

很好。现在,为了使其正常工作,您可以正常使用 YouTube 播放器。我建议使用片段,因为必须扩展现有的 Activity class 可能是个问题。在 OnInitializationSuccess 回调中使用 player.setPlayerStyle(PlayerStyle.CHROMELESS) 删除播放器的所有控件。

现在,要让您的控件在 Player 之上而不暂停,您需要使用 DialogFragment(单独使用 Dialog 可能有效,但再次使用 Fragment 带来更多控制你可以做什么):

  • 创建您自己的 DialogFragment
  • 子class
  • 覆盖 onCreate(Bundle) 并调用 setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Translucent_NoTitleBar)
  • 覆盖 onCreateView(LayoutInflater, ViewGroup, Bundle) 并根据需要在此处重新创建 Activity 布局。我正在使用 Kotlin 和 Anko,所以一切对我来说都是动态的,我没有 XML。无论如何,重新创建布局但没有最终视图(结果应该完全不可见)。
  • 现在,在替换播放器的视图中,假设您使用了 FrameLayout,您可以像播放器的 FrameLayout
  • 一样添加控件
  • 覆盖 onStart() 并在现在创建的 Dialog 上调用以下方法,以确保您的对话框是全屏和透明的:

    Dialog dialog = getDialog();
    dialog.setCanceledOnTouchOutside(false);
    dialog.setCancelable(false);
    dialog.setOnKeyListener(new OnKeyListener() {
    
        @Override
        public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                // TODO Dismiss the Dialog AND call onBackPressed() on the underlying Activity
                return true;
            } else {
                return false;
            }
        }
    
    });
    
    Window window = getWindow();
    window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
    WindowManager.LayoutParams layoutParams = window.getAttributes();
    layoutParams.setDimAmount(0f);
    layoutParams.setFlags(layoutParams.getFlags() | WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    window.setAttributes(layoutParams);
    

现在你必须处理你的控件,让它们在计时器后消失,等等。 只需确保将覆盖播放器的所有内容放在对话框(片段)内的某个位置即可。

我不确定我在这里列出的所有内容都是强制性的,但我就是这样做的,而且效果很好。

注意:正如我所说,我正在使用 Kotlin 和 Anko,我已经有几个月没有写 Java 了,所以这里提供的任何代码都可能有小错别字。如果您看到任何错误,请告诉我。

奖金:我如何处理全屏。

为了处理全屏模式,我只是将 Dialog 中除了播放器和匹配视图(对我来说是 FrameLayout)之外的所有内容的可见性设置为 GONE,make确保 LayoutParams' 这两个视图的宽度和高度设置为 MATCH_PARENT。要退出全屏,只需将您更改回的所有视图的可见性设置回 VISIBLE