
通过阅读本文,您将获得以下知识点:
一、设置Simulate secondary displays二、实现副屏异显三、实现效果
Android SDK 提供了Display类,在主屏幕外的扩展屏幕上显示不同于主屏幕UI,扩展屏幕UI显示本质上显示了系统级别Dialog,我们可以自己做View加入到此Dialog显示在中间。可以有一个或多个扩展屏幕,在实际应用中需要底层驱动的支持。在官方模拟器中,我们可以模拟一个副屏幕进行调试(当然,除了模拟器,我们的手机也可以模拟)以Android以官方模拟器为例,说明如何进行双屏异显调试。
一、设置Simulate secondary displays
打开模拟器"设置-开发者选项"在列表中找到界面"Simulate secondary displays"条目。点击后,在弹出的对话框中选择副屏的分辨率:
image
比如我们选720p,副屏幕的窗口立即出现在模拟器屏幕的左上角,其显示内容默认与主屏幕显示一致:
image
副屏窗口就是一个Dialog,可拖动,使其显示在合适的位置。
二、实现副屏异显
因为副屏默认显示与主屏一致,如果要实现双屏异显,我们需要在APP在中间开发,在副屏中添加自定义布局进行显示。1、申请权限AndroidManifest.xml添加两个权限:
<uses-permission android:name= "android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name= "android.permission.SYSTEM_OVERLAY_WINDOW"/>
因为android 6.0及之后 android.permission.SYSTEM_OVERLAY_WINDOW启用需要系统动态授权,所以在APP启动时加入如下代码进行动态授权:
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { //启动Activity让用户授权 if (!Settings.canDrawOverlays(this)) { val intent: Intent = Intent( Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse( "package:$packageName")) startActivityForResult(intent, 1010) } }
该系统将弹出授权窗口并打开
image
二、获取副屏Display对象
///获取显示管理服务代理对象 val displayManger = activity.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager? ///当前副屏Display private var currentDisplay: Display? = null
displayManger?.run { ///取所有副屏对应的副屏Display列表 val displays = getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION) if (!displays.isEmpty()){ val display = displays.find { it.isValid } //取第一个有效的Display ///无副屏访问新的副屏 if (currentDisplay == null) { 保存副屏Display currentDisplay = display } } }
第一步"设置Simulate secondary displays"我们已经设置了副屏,所以currentDisplay不会为空。3、初始化Context与WindowManager
//副屏Context private var presentationContext: Context? = null ///副屏窗口管理器 private var presentationWindowManager:WindowManager? = null
val displayContext: Context = activity.createDisplayContext(display) val wm = displayContext.getSystemService(WINDOW_SERVICE) as WindowManager presentationContext = object :ContextThemeWrapper(displayContext, android.R.style.Theme){ override fun getSystemService(name: String): Any { if (WINDOW_SERVICE == name) { return(wm) } return super.getSystemService(name) } } presentationWindowManager = (presentationContext as ContextThemeWrapper).getSystemService(Context.WINDOW_SERVICE) as WindowManager
加入副屏View布局只显示纯蓝色背景:default.xml
<?xml version="1.0" encoding="utf-8"?> <View xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/holo_blue_dark"/>
以下是向副屏窗口添加的内容View参考代码:
//通过布局id生成View val inflater = LayoutInflater.from(presentationContext!!) val view = inflater.inflate(R.layout.default, null) //最终副屏会显示default.xml的内容 presentationWindowManager?.addView(view,buildLayoutParams())
buildLayoutParams函数:
@SuppressLint("InlinedApi") private fun buildLayoutParams():WindowManager.LayoutParams { if(Build.VERSION.SDK_INT >= 26){ return WindowManager.LayoutParams( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, 0, 0, TYPE_APPLICATION_OVERLAY, //FIRST_SYSTEM_WINDOW 38 0, PixelFormat.TRANSPARENT ) } else { return WindowManager.LayoutParams( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, 0, 0, WindowMnager.LayoutParams.TYPE_SYSTEM_ALERT,
0, PixelFormat.TRANSPARENT
)
}
}
说明一下:Android8.0及以后只能使用TYPE_APPLICATION_OVERLAY窗口类型来创建悬浮窗。(其它窗口类型在8.0已经被废弃掉)
三、实现效果
image
副屏还可以显示其它更复杂的布局,也可以显示图片与播放视频,如下是播放视频的截图:
最后的问题:副屏是否支持触摸?目前我了解所知,原生并不支持副屏触摸动作,但是修改源码是可以达到的(主要是修改触控事件的向上分发逻辑,因为分发时只有一个主屏)。可以参考:https://www.jianshu.com/p/572eaa37ddd3
另外Android自带一个系统组件Presentation,可以简化多屏异显,其实质也是封装了上面的过程。
参考链接:https://www.jianshu.com/p/a669ecc7bc9b
Android 开发干货集锦
至此,本篇已结束。转载网络的文章,小编觉得很优秀,欢迎点击阅读原文,支持原创作者,如有侵权,恳请联系小编删除,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!
点击阅读原文,为大佬点赞!