Android N 预览版本支持画中画(Picture in Picture)模式进行视频的播放。画中画是多窗口模式的一种特殊类型,主要用于后台播放视频。Android TV设备早已经支持画中画模式。在多窗口模式中,用户仍然可以看到处于暂停状态的应用,而且应用在暂停状态下可能仍需要继续其他操作。例如,处于暂停模式但可见的视频播放应用应该继续显示视频。Android官方建议播放视频的Activity不要在onPause()暂停视频,应在onStop()暂停视频,在onStart()恢复播放。先看下画中画播放视频的情景:
在Android N 版本中,你可以在manifest文件对Activity是否支持多窗口形式进行设置。根Activity的属性设置适用于其任务栈所有Activity。支持多窗口设置如下:
android:resizeableActivity="true"
如果设为true,Activity将可以分屏和以自由模式启动;如果为false,则不支持分屏。该属性默认为true。如果需要
支持画中画模式,设置如下:
android:supportsPictureInPicture="true"
和多窗口布局属性相关的包括:默认高度、默认宽度、初始位置、最小高度、最小宽度。具体如下:
<layout
android:defaultHeight="500dp"//设置默认高度
android:defaultWidth="600dp"//设置默认宽度
android:gravity="top|end"//设置初始位置
android:minimalHeight="450dp"//设置最小高度
android:minimalWidth="300dp"//设置最小宽度
/>
如果需要查询当前Activity是否处于多窗口模式,可以调用以下方法:
Activity.isInMultiWindowMode()
如果需要查询当前Activity是否处于画中画模式,可以调用以下方法:
Activity.isInPictureInPictureMode()
Activity 进入或退出多窗口模式时系统将调用如下方法。 在 Activity 进入多窗口模式时,系统向该方法传递 true 值,在退出多窗口模式时,则传递 false 值。
Activity.onMultiWindowModeChanged()
Activity 进入或退出画中画模式时系统将调用如下方法。 在 Activity 进入画中画模式时,系统向该方法传递 true 值,在退出画中画模式时,则传递 false 值。
Activity.onPictureInPictureModeChanged()
如果需要在画中画模式中启动Activity,可以调用如下方法:
Activity.enterPictureInPictureMode()
在多窗口模式中启动新 Activity,可以使用标志 Intent.FLAG_ACTIVITY_LAUNCH_TO_ADJACENT。如果设备处于分屏模式,系统会尝试在启动系统的 Activity 旁创建新 Activity,这样两个 Activity 将共享屏幕。如果设备处于自由形状模式,则在启动新 Activity 时,用户可通过调用 ActivityOptions.setLaunchBounds() 指定新 Activity 的尺寸和屏幕位置。值得注意的是,如果您在任务栈中启动 Activity,该 Activity 将替换屏幕上的 Activity,并继承其所有的多窗口属性。 如果要在多窗口模式中以单独的窗口启动新 Activity,则必须在新的任务栈中启动此 Activity。Activity处于画中画模式时,生命周期应该这样操作:
@Override
protected void onStop() {
super.onStop();
//进入画中画模式,调用onPause方法,而不是onStop方法
//暂停视频的播放
mMovieView.pause();
}
@Override
protected void onRestart() {
super.onRestart();
//恢复视频的播放
mMovieView.showControls();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
//屏幕发生旋转,自适应全屏
adjustFullScreen(newConfig);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {//window获得焦点,自适应全屏
adjustFullScreen(getResources().getConfiguration());
}
}
Activity进入或者画中画时,需要重写onPitctureInPictureModeChanged方法:
@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode);
if (isInPictureInPictureMode) {
// 开始接受来自画中画点击响应事件
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null || !ACTION_MEDIA_CONTROL.equals(intent.getAction())) {
return;
}
// 点击后的回调
final int controlType = intent.getIntExtra(EXTRA_CONTROL_TYPE, 0);
switch (controlType) {
case CONTROL_TYPE_PLAY:
mMovieView.play();
break;
case CONTROL_TYPE_PAUSE:
mMovieView.pause();
break;
}
}
};
registerReceiver(mReceiver, new IntentFilter(ACTION_MEDIA_CONTROL));
} else {
// 退出画中画 模式,注销广播,不再接收点击响应事件
unregisterReceiver(mReceiver);
mReceiver = null;
if (mMovieView != null && !mMovieView.isPlaying()) {
mMovieView.showControls();
}
}
}
视频状态发生改变时,调用以下方法按钮和文字的状态:
/**
* 处于画中画模式,更新播放/暂停状态
*
* @param iconId 图标的id
* @param title 标题
* @param controlType 控制类型:播放/暂停
* @param requestCode 使用PendingIntent的请求码
*/
void updatePictureInPictureActions(@DrawableRes int iconId, String title, int controlType,
int requestCode) {
final ArrayList<RemoteAction> actions = new ArrayList<>();
//当用户点击控制按钮时,PendingIntent会被调用
final PendingIntent intent = PendingIntent.getBroadcast(MainActivity.this,
requestCode, new Intent(ACTION_MEDIA_CONTROL).putExtra(EXTRA_CONTROL_TYPE, controlType), 0);
final Icon icon = Icon.createWithResource(MainActivity.this, iconId);
actions.add(new RemoteAction(icon, title, title, intent));
actions.add(new RemoteAction(
Icon.createWithResource(MainActivity.this, R.drawable.ic_info_24dp),
getString(R.string.info), getString(R.string.info_description),
PendingIntent.getActivity(MainActivity.this, REQUEST_INFO,
new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.info_uri))),
0)));
mPictureInPictureArgs.setActions(actions);
//设置画中画参数
setPictureInPictureArgs(mPictureInPictureArgs);
}
视频播放回调,包括播放、暂停和最小会窗口,每个接口会调用上面介绍到的方法更新状态:
/**
* 视频播放的回调
*/
private MovieView.MovieListener mMovieListener = new MovieView.MovieListener() {
@Override
public void onMovieStarted() {
// 处于画中画模式,播放视频时,显示暂停按钮
updatePictureInPictureActions(R.drawable.ic_pause_24dp, mPause, CONTROL_TYPE_PAUSE,
REQUEST_PAUSE);
}
@Override
public void onMovieStopped() {
// 处于画中画模式,暂停视频时,显示播放按钮
updatePictureInPictureActions(R.drawable.ic_play_arrow_24dp, mPlay, CONTROL_TYPE_PLAY,
REQUEST_PLAY);
}
@Override
public void onMovieMinimized() {
// 进入画中画模式,播放窗口最小化
minimize();
}
};
好了,以上是对Android N多窗口和画中画模式的介绍。如果这篇文章对你有帮助,可以点个赞。