一、Presentation 介绍
要了解 API 的具体调用,推荐先查看官方的文档:Presentation文档
Android 从4.2开始支持双屏显示,开发时需 minSdkVersion >= 17 。Android 连接两个屏幕时,自动分配主屏和副屏,主屏显示正常的 Activity 界面,副屏通过创建 Presentation 类来实现。
通过查看 Presentation 继承关系可知,Presentation 继承自 Dialog,创建的时候需要遵循 Dialog 相关要求。当和 Presentation 相关联的屏幕被移除后,Presentation 也会自动的被移除,所以当 Activity 处于 pause 和 resume 的状态时,Presentation 也需要特别注意当前显示的内容的状态。
二、Presentation 实现
首先建立一个空工程,然后创建MyPresentation类继承Presentation类,由于我需要在副屏界面创建2个Button,并监听点击事件所以我implements了View.OnClickListener接口。
//MyPresentation.java
package com.example.multidisplaydomo;
import android.app.Presentation;
import android.content.Context;
import android.os.Bundle;
import android.view.Display;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MyPresentation extends Presentation implements View.OnClickListener{
public MyPresentation(Context context, Display display){
super(context,display);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mypresentation);
Button mypresentation_button_1 = (Button) findViewById(R.id.mypresentation_button_1);
Button mypresentation_button_2 = (Button) findViewById(R.id.mypresentation_button_2);
mypresentation_button_1.setOnClickListener(this);
mypresentation_button_2.setOnClickListener(this);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.mypresentation_button_1:
Toast.makeText(getContext(),"mypresentation_button_1 onClick",Toast.LENGTH_SHORT).show();
break;
case R.id.mypresentation_button_2:
Toast.makeText(getContext(),"mypresentation_button_2 onClick",Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
}
然后在Main Activity中通过DisplayManager取得系统屏幕数量,如果系统屏幕数量大于1,就显示副屏界面。
//MainActivity.java
package com.example.multidisplaydomo;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Presentation;
import android.content.Context;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button_1 = (Button) findViewById(R.id.button_1);
Button button_2 = (Button) findViewById(R.id.button_2);
button_1.setOnClickListener(this);
button_2.setOnClickListener(this);
DifferentDisplay();
}
void DifferentDisplay() {
DisplayManager mDisplayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
Display[] displays = mDisplayManager.getDisplays();
if(displays.length > 1) {
Display display = displays[1];
Presentation presentation = new MyPresentation(this, display);
presentation.show();
}
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_1:
Toast.makeText(this,"button_1 onClick",Toast.LENGTH_SHORT).show();
break;
case R.id.button_2:
Toast.makeText(this,"button_2 onClick",Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
}
activiyt_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="7dp"
tools:ignore="MissingConstraints" />
<Button
android:id="@+id/button_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="7dp"
tools:ignore="MissingConstraints" />
</LinearLayout>
mypresentation.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/mypresentation_button_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="7dp"
tools:ignore="MissingConstraints" />
<Button
android:id="@+id/mypresentation_button_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="7dp"
tools:ignore="MissingConstraints" />
</LinearLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW"/>
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MultiDisplayDomo"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
</application>
</manifest>
三、如何让副屏常驻?
因为 Presentation 相当于在主屏的 Activity 上创建了一个特殊 Dialog,所以 Presentation 会随着主屏 Activity 的生命周期显示隐藏,如何让副屏常驻,不随主屏 Activity 退出。在 Dialog 中,我们知道可以通过创建系统级弹框的方式来做,Presentation 中也是一样。
添加系统权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
在 Presentation 中添加系统弹框代码
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
} else {
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}
注意:
-
Presentation 实际上是一个特殊的 Dialog,因此在 Presentation 中无法创建 Fragment、Popupwindow 等组件。
-
Presentation 显示的副屏和主屏的尺寸是不相同的,绘制 UI 时需特别注意。
在虚拟机运行前需要先把模拟机添加第二块屏幕,打开虚拟机菜单,然后点击右侧的Extended Controls,然后点击Displays,再点击Add secondary display,如下图所示:
Domo代码: