如何退出画中画模式?

47

我们有enterPictureInPictureMode()方法将一个活动从其当前形式移动到画中画表示。

除了销毁活动,我们如何恢复活动到其正常状态的方法?Activity上没有exitPictureInPictureMode()leavePictureInPictureMode()或者janeGetMeOffThisCrazyPictureInPictureModeThing()方法,并且文档似乎也没有涵盖其他替代方法。

我需要一个适用于Android O的解决方案,用于移动设备的画中画模式,如果适用于Android TV,那就太棒了!

更新2017-04-08:如果您想要在用户点击X按钮退出画中画模式时返回正常模式,您可以这样做:

  @Override
  public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
    super.onPictureInPictureModeChanged(isInPictureInPictureMode);

    if (!isInPictureInPictureMode) {
      getApplication().startActivity(new Intent(this, getClass())
        .addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT));
    }
  }
关键是调用startActivity()启动当前活动,并使用FLAG_ACTIVITY_REORDER_TO_FRONT将其重新排序到前面。对于singleTask活动,需要在一些非Activity上下文中调用该活动,例如Application单例。这似乎不会触发onStop()onStart(),但它会触发onNewIntent()(使用您传递给startActivity()的任何Intent)。

你是否遵循了使用单个播放活动进行画中画的建议? - ianhanniballake
1
@ianhanniballake:是的,但这并没有解决我的问题。我不想切换内容,我只是想将内容扩展回其原始大小,而不会中断正在进行的操作。例如,用户决定进入 PiP 模式,意识到视频太小了,想要再次扩大它。 - CommonsWare
1
是的,像你提到的那样并没有这样的方法。我在 PiP 方面的工作不多,但你可以使用 onPictureInPictureModeChanged 来跟踪正常模式和 PIP 模式切换事件。 - Pravin Divraniya
很棒的问题,让我去看了一下多窗口支持,提到了电视上的画中画和手持设备上的分屏,意思相同。另外,我在想,如果汤姆、迪克和哈里开发的应用程序互相覆盖,强制/滥用janeEscapeLoopPiP,那么简可能会疯掉,所以...也许把这部分留给用户输入/操作更好。听起来就像是在会议中提供“disconnectCall”方法给电话API一样。 - Pararth
@CommonsWare 有没有解决你的问题的好运? - Anchit Mittal
显示剩余2条评论
6个回答

16
  1. 将活动移到后面

activity.moveTaskToBack(false /* nonRoot */);
  • 将应用程序恢复到前台显示

  • Intent startIntent = new Intent(PipActivity.this, PipActivity.class);
    startIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
    activity.startActivity(startIntent);
    

    这个模式似乎用于多窗口。希望这可以帮到你,我自己无法尝试,因为我的所有模拟器图像都出现了“IllegalStateException:enterPictureInPictureMode:设备不支持画中画模式”的错误... - rds
    太狡猾了!不幸的是,我在使用 moveTaskToBack() 时遇到了困难。参考文档显示 PiP 活动是 singleTask 的。moveTaskToBack() 似乎影响应用程序的原始任务,而不是 PiP 活动的任务。我可能还需要进行这个 hack。我会继续尝试这个方法,因为你的方法看起来很有前途。谢谢! - CommonsWare
    我刚刚尝试了这个解决方案,onDestroy() 被调用了,因此它并没有回答你的问题。事实上,在进入画中画时它被调用了一次,在启动意图时它又被调用了一次,尽管设置了 singleTask 和 FLAG_ACTIVITY_REORDER_TO_FRONT。 - rds
    我将授予此答案赏金,因为它最接近解决方案。但是我不会接受它,因为它并不是真正的解决方案。:-) 不过还是非常感谢! - CommonsWare
    我有一个问题,我现在处于画中画模式,当我点击pip时,会显示一个白色的方块以将其最大化,但底部的播放和暂停按钮显示在视频/ exoplayer之外,如何将播放暂停按钮显示在中心,就像最大化的白色框那样。 - Gyan Swaroop Awasthi

    10

    我遇到了同样的问题:

    • MainActivity 打开启用了 PIP 模式的 VideoPlayerActivity
    • 按返回按钮进入 PIP 模式。
    • 再次按返回按钮,直到从 MainActivity 退出。
    • 在 PIP 窗口上点击关闭(X)按钮。
    • 打开应用程序,它将打开 VideoPlayerActivity

    虽然以上解决方案都对我不起作用,但我发现监听 X 按钮的唯一方法是覆盖 onStop

    当从 PIP 恢复活动时,会调用 onResumeonPictureInPictureModeChanged,当单击 X 按钮时,会调用 onStoponPictureInPictureModeChanged

    因此,我尝试在已经调用了 onStop 时,在 onPictureInPictureModeChanged 中调用 finish()

    override fun onStop() {
        super.onStop()
        onStopCalled = true
    }
    
    override fun onResume() {
        super.onResume()
        onStopCalled = false
    }
    
    override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) {
            if (isInPictureInPictureMode) {
                // ...
            } else {
                if (onStopCalled) {
                    finish()
                }
            }
        }
    

    1
    onStop方法在onPictureInPictureModeChanged方法之前被调用是有保证的吗?某些设备(使用Android 8和9)中,onPictureInPictureModeChanged方法会在onStop方法之前被调用,导致我们无法结束活动。我已经为此苦苦挣扎了几天。 - TiagoPereira17
    @TiagoPereira17 我知道这已经有一段时间了,但你是否有任何想法,能否找到解决这些设备问题的办法? - mehul bisht

    3
    我认为该活动不能决定退出画中画模式。
    来自Android O API预览文档

    进入PIP模式的活动进入暂停状态,但仍保持启动状态。如果用户点击PIP活动,则系统会显示一个菜单供用户交互;当它处于PIP状态时,没有触摸事件到达该活动。

    该活动将通过onPictureInPictureModeChanged()被通知。

    4
    注意:我在谷歌工作(虽然不是在Android部门),但我也找不到任何关于janeGetMeOffThisCrazyPictureInPictureModeThing()或类似方法的调用。 - rds
    1
    活动应该能够离开 PiP 模式:只需 finish() 活动并创建一个新实例即可。即使有过渡效果,这可能会导致 UI 卡顿,我希望我们有一个 API 来避免这种情况。不过还是谢谢! - CommonsWare
    我真的不认为销毁/重建实例和改变模式是一回事。 - rds
    1
    顺便说一下,我已经提出了一个请求,为这种情况添加一些内容 - CommonsWare
    @CommonsWare 你有关于这个问题的任何想法吗?我正在苦苦挣扎。 - Gustavo Forero Carvajal
    1
    @GustavoForeroCarvajal:Google拒绝了功能请求,而且我已经好几年没有使用过PiP,所以我不知道是否有任何更新。抱歉! - CommonsWare

    3
    我找到了一种100%可靠的方法来实现这一点。
    1. 在清单文件中,为你的PIP活动设置taskAffinity属性,比如“com.package.pip”。无论是什么都可以,只要与默认任务亲和度——即包名不同即可。这将导致它启动在一个完全独立的堆栈里,就像另一个应用程序一样。
    2. 每当你想退出PIP时,从另一个活动中使用startActivity(new Intent(this, PipActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))启动它。
    我刚才看了一下当应用程序的主要活动当前处于PIP模式时,从启动器启动它会发生什么,并且我想我可以复制这个操作,确实可以。

    0

    官方文档中提到,PIP窗口会出现一个菜单,让您切换到全屏模式。

    PIP窗口的大小为240x135 dp,并显示在屏幕的四个角之一,由系统选择。用户可以通过按住遥控器上的Home按钮来打开PIP菜单,以切换PIP窗口到全屏模式或关闭PIP窗口。如果主屏幕上开始播放另一个视频,则自动关闭PIP窗口。

    您还可以覆盖PIP更改事件,以处理用户切换PIP模式时的UI元素。

    链接到onPictureInPictureModeChanged

    @Override
    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
        if (isInPictureInPictureMode) {
            // Hide the controls in picture-in-picture mode.
            ...
        } else {
            // Restore the playback UI based on the playback status.
            ...
        }
    }
    

    那似乎是电视的说明。在Android O手机(Nexus 5X)上,有一个关闭按钮,可以销毁活动。没有遥控器。长按窗口可以移动它。似乎没有用户可访问的手段将活动恢复到正常模式。但这些都不表明我如何以编程方式离开PiP模式,这是这个问题的核心。谢谢! - CommonsWare

    -1
    根据来自另一个stackoverflow博客最新的答案https://dev59.com/21YN5IYBdhLWcg3wsZxR#71797433,应该这样做。对我来说它很有效。
    @Override
    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {
    
        if (getLifecycle().getCurrentState() == Lifecycle.State.CREATED) {
            //when user click on Close button of PIP this will trigger.
            finishAndRemoveTask();
    
        }
        else if (getLifecycle().getCurrentState() == Lifecycle.State.STARTED){
            //when PIP maximize this will trigger
        }
        super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
    }
    

    问题不是关于最大化/关闭触发器。 - Drunken Daddy
    醉爸爸,是的,问题不在于最大化。而是关于如何离开PIP,答案就在If语句中,而不是else if语句中。如果你愿意,可以忽略else if语句。由于某种未知原因,if语句中的代码会让你离开PIP。我在我的应用程序中实现了它,效果很好。 - Yosidroid

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接