Jetpack WindowManager,Android 折叠屏官方适配方案!

4,482 阅读6分钟

1. 前言

是的,Jetpack 又添加新成员了,那就是WindowManager,它是干什么用的呢?本文就带你一起了解一下。

WindowManager是Android Jetpack的最新功能,旨在帮助APP开发人员支持新的设备尺寸,并为新旧平台版本上的各种Window Manager功能提供通用的API交互。现在,最初的版本面向可折叠设备,将来的版本将扩展为支持更多的显示类型和窗口功能。

2. 为什么我们需要它?

现在,市场上新出了一些可折叠屏设备,它们提供了一组独特的硬件功能。针对这些新设备和外形来优化你的APP,能给用户带来与众不同的体验,并且让用户能充分利用他们所使用的设备。

例如,三星Galaxy Z Flip是翻盖式设备,支持折叠和部分折叠状态(三星称为Flex模式)。当设备处于部分折叠状态时,该应用可以优化其布局,并将底部的控件与顶部的其余内容分开。如相机或者图库可能会如下适配:

用户可以将手机放在平坦的地方(例如在桌子上),然后使用屏幕的下半部分导航和与应用交互。

Jetpack WindowManager 库的目标就是,为市面所有类型的可折叠设备提供单一的上层API,以便开发者可以这对不同类型的类型的设备进行适配,而不是为每一个设备模型都单独适配。

在1.0.0版中,该库提供了有关可折叠设备的两个物理属性的信息-显示特征设备状态

  • DisplayFeature: 这个API可以识别屏幕的表面是否连续,比如铰链或者折叠。
  • DeviceState: 这个API通过定义的状态列表来(例如CLOSEDOPENEDHALF_OPENED等)提供手机的当前状态。

3. 显示特征

单个显示面板或多个显示配置可能具有不同的特征,这些特征会在连续的屏幕表面产生干扰,比如折叠铰链弯曲区域刘海切口。如果应用程序窗口中存在此类中断,则可以调整内容在窗口中的布局和位置,以避免此类区域显示异常,或者将它们用作自然分隔。这也能展现此类设备的优势。

每个显示特征区都可以通过其在窗口坐标空间中的边界矩形及其类型来表征。矩形指示了特征的物理范围。特征的类型将有助于定义如何对待它。比如说,某些特征可以创建物理分隔和/或非交互区域(例如,两个显示面板之间的铰链,显示切口),而其他特征可以用作逻辑分隔符(例如,折叠)。

public class DisplayFeature {
    private Rect mRect;
    private @Type int mType;
    ...
}

Jetpack WindowManager 的第一个版本仅包含两种类型的功能:TYPE_FOLDTYPE_HINGE

特别对于TYPE_FOLD,边界矩形应为zero-high (0, y, width, y)或者zero-wide (x, 0, x, height),这表明没有不可访问的区域,但是它仍然报告屏幕上的位置。

4. 设备状态

取决于铰链硬件设计,不同的可折叠设备可以具有几种中间状态:关闭部分打开完全打开(平坦表面)或翻转

使用Jetpack WindowManager时,APP可以根据这些设备状态提供不同的功能。这些状态定义为不同的姿势:

@IntDef({
    POSTURE_UNKNOWN,
    POSTURE_CLOSED,
    POSTURE_HALF_OPENED,
    POSTURE_OPENED,
    POSTURE_FLIPPED
})
public @interface Posture{}

每个设备可以获取上面定义的这些姿势的任何子集,具体取决于它们的硬件和所需的用户体验。

4. 如何使用?

说了这么多,到底该如何使用呢?

别猴急~慢慢来...

首先,需要将Window Manager 的maven仓库地址添加到项目中,在app 下面的build.gradle中添加依赖:

dependencies {
    implementation "androidx.window:window:1.0.0-alpha01"
}

如上图所示,假设你想在可折叠设备上拆分Google Duo等应用的用户界面。通常,在设备的物理配置和状态为用户造成逻辑隔离的情况下,这样做是有意义的。

例如,Galaxy Z Flip在“ Flex”或“对折”模式下会产生这种逻辑上的分离。因此,您需要知道折叠在应用程序窗口中的位置以及设备的状态

首先,从Activity获取androidx.window.WindowManager的实例。

var windowManager = WindowManager(this /* context */, null /* windowBackend */)

要注意这里的参数

  • 第一个参数,Context用于初始化WindowManager实例并将其连接到屏幕上的可视实体。因此,它必须是可视的Context,这意味着它只能是Activity或一个ContextWrapper

  • windowBackend 是该库信息的提供者,在此处传递null表示将使用默认设备信息,并且当应用程序在常规手机上运行时,库将报告无任何显示特征未知设备状态。不过,您还可以传递androidx.window.WindowBackend的自定义实现,以模拟任何类型的可折叠设备,而无需访问物理硬件。我们在示例APP中有一个这样的示例:github.com/android/use…

因为只有在存在逻辑硬件分离时,才分离UI,有两种情况:

1、 显示特征的类型为TYPE_HINGE,并且活动窗口内始终存在物理分隔。

2、或者显示特征的类型为Type_Fold,并且屏幕状态不平坦(例如,不是POSTURE_OPENED)。特别是对于Galaxy Z Flip,我们会对POSTURE_HALF_OPENED感兴趣。

对于折叠的情况,我们需要了解设备状态变化,因此我们需要注册DeviceState变化监听器:

windowManager.registerDeviceStateChangeCallback(
    mainThreadExecutor /* Executor */,
    callback /* Consumer<DeviceState> */)

在回调中,您可以更改设备状态并根据需要更新UI。 最后,我们需要获取活动窗口中的实际显示特征。

val displayFeatures = windowManager.windowLayoutInfo.displayFeatures

根据你的Activity处理(或不处理)配置更改的方式,你可能需要在“Activity”生命周期的不同时间点询问它。然后在window decor view 的布局上应用,以确保在Activity状态更改后它始终是最新的。代码如下:

window.decorView.doOnLayout {
    val displayFeatures =
        windowManager.windowLayoutInfo.displayFeatures
    ...
}

请注意,显示特征的位置是相对于活动窗口坐标空间计算的,因此,只能在将Activity附加到窗口之后才能提供。在此之前请求信息将引发异常。

5. 最后

强烈建议运行查看官方Demo 来探索Jetpack WindowManager,它还包含了如何计算显示特征在View 机构中的位置的示例,还有一些示例,如在找到分割显示特征时自动分割布局等等。Demo地址:github.com/android/use…

作者 | Kenneth Ford 译者 | 依然范特稀西 编辑 | 依然范特稀西 地址 | medium.com/androiddeve…

文章首发于公众号:「 技术最TOP 」,每天都有干货文章持续更新,可以微信搜索「 技术最TOP 」第一时间阅读,回复【思维导图】【面试】【简历】有我准备一些Android进阶路线、面试指导和简历模板送给你