百度文库 旅游网站建设方案书,国学网站源码,做的好的地方网站,wap网站的开发自 2019 年三星发布了第一台#xff08;柔宇不算#xff09; Galaxy Z Fold 之后#xff0c;Android 厂商们都陆续跟进了各自的可折叠方案#xff0c;之后折叠屏手机市场一直保持快速增长#xff0c;例如 2023 年上半年整体销量 227 万台#xff0c;同比增长 102.0%。
虽…自 2019 年三星发布了第一台柔宇不算 Galaxy Z Fold 之后Android 厂商们都陆续跟进了各自的可折叠方案之后折叠屏手机市场一直保持快速增长例如 2023 年上半年整体销量 227 万台同比增长 102.0%。
虽然对比上半年手机总体出货量 1.3 亿台只能算是零头但是不可否认如今开发者的 App 遇到可折叠手机的概率并不低特别这部分用户大概率还属于「高产值」用户。 所以 2023 年开始折叠屏适配也逐步开始成为 Android 的主流 KPI 之一那么不适配的话会怎么样适配的话又是通过什么方式本篇将带你深入了解这个话题。 ⚠️本文超长可收藏以备不时之需。 Letterboxing 模式
首先如果不适配的话你的应用大概率不一定会是 Letterboxing 模式的显示方式可能你会看到 App 以如下图所示的方式存在也就是当应用的宽高比和屏幕比例不兼容时App 可能会以 Letterbox 模式打开。 一般是 App 锁死旋转方向和采用了不可调整大小。 当然是否进入 Letterboxing 模式和 TargetSDK 版本、 App 配置和屏幕分辨率都有关系并且不同 OS 版本上 Letterboxing 模式的呈现方式也可能有所不同例如 Android 12API 31开始引入了 Letterboxing 增强功能可由手机厂家配置支持 圆角 窗口支持圆角系统栏透明度覆盖 App 的状态栏和导航栏支持半透明可配置的宽高比可以调整 App 的宽高比改善应用的外观 12LAPI 32添加了 可配置位置在大屏幕上设备厂商可以将应用配置在显示屏的左侧或右侧。重启按钮设备厂商可以为尺寸兼容模式的重启按钮赋予新的外观。尺寸兼容模式可以让 App 的宽或者高尽可能充满屏幕 当系统确定可以通过重新缩放应用以填充显示窗口来改进 Letterboxing 的显示时Android 会将 App 置于尺寸兼容模式这时候系统显示一个重启控件确定后会重新创建 App 进程、重新创建 Activity 并重绘进行适配。 Android 13API 33添加了一个用户引导的提示对话框
那么什么时候会进入 Letterboxing 模式 一般可以简单理解为
android:resizeableActivityfalse 下应用声明的宽高比与容器不兼容时例如屏幕宽度超过 android:maxAspectRatio 。setIgnoreOrientationRequest(true) 下系统设置忽略屏幕方向后横向打开强制竖屏的界面。
这里的核心点其实是 resizeableActivity 它用于声明系统是否可以调节 App 大小去适应不同尺寸的屏幕 其实严格来说 resizeableActivity 不一定会导致应用一定进入 Letterboxing 模式这也 API 版本有关系
在 Android 7.0API 24引入了分屏模式配置 resizeableActivity。在 Android 11API 30及更低版本上用于配置 App 是否支持多窗口模式如果 false 就不支持会进入 Letterboxing 模式。在 Android 12API 31及更高版本上无论 resizeableActivity 设置什么App 都会支持大屏幕 (sw 600dp) 上的多窗口模式所以仅用于指定 App 是否支持小屏幕sw 600dp上的多窗口模式。 sw 600dp 可以简单理解为你的屏幕的绝对宽度大于 600dp 那有的人就说了如果我在 Android 12 就使用 android:resizeableActivityfalse 然后什么都不适配会怎么样我只能说「有一定概率」会如下图所示一样直接 crash 。 那是不是我不使用高版本的 TargetSDK 就可以不用工作适配了呢
也不完全是至少你需要对你的 App 或者 Activity 进行一些简单的配置因为早在 Android 7.0API 24开始resizeableActivity 的默认值就被改为 true。
所以如果你不想适配大屏模式 UI希望进入 Letterboxing 模式还是需要手动在 AndroidManifest 中的 application 或对应的 Activity 配置上 android:resizeableActivityfalse 。
另外Letterboxing 模式的显示模式和 maxAspectRatio 也有关当屏幕比例超过 maxAspectRatio 时才会用黑边填充一般官方建议把 maxAspectRatio 设为 2.4 (12 : 5)配置方式也和 API Level 有关系 Android 8.0 及以上可以通过 android:maxAspectRatio 配置 activity android:name.MainActivityandroid:maxAspectRatio2.4 / Android 8.0 以下可以通过 meta-data android.max_aspect 配置 meta-data android:nameandroid.max_aspect android:value2.4 / PS 如果 resizeableActivity 是true maxAspectRatio 会不生效。 如图是前面提到 Android 12LAPI 32的重启按钮可以让 App 一端尽可能适配屏幕减少黑边。 还有一点在折叠屏展开和闭合的时候在屏幕发生了变化时系统可能会销毁并重新创建整个 Activity 所以我们需要配置 android:configChanges 来防止重启
android:configChangesscreenLayout|smallestScreenSize|screenSize最后还需要注意 supports_size_changes 如果不想支持多窗口模式但是又可能会因为系统强迫进入多窗口模式然后又不希望每次都被重启那么可以配置 supports_size_changes 来保证运行的连续性。
meta-dataandroid:nameandroid.supports_size_changes android:valuetrue /所以这里简单做个总结就是 当应用的宽高比与其屏幕比例不兼容App 锁死旋转方向和大小时会进入 Letterboxing 模式 resizeableActivity 的效果主要看 TargetSDK 版本 Android 12API 31及更高版本上可能还是会进去分屏模式 maxAspectRatio 的作用主要看 resizeableActivity 配置 android:configChanges 和 supports_size_changes 防止重启 Activity 保证连续性
官方适配支持
接下来就是介绍适配方案首先我们看这张图其实官方已经根据使用场景为我们定义好使用建议其中关键的几个信息有
ComposeActivity EmbeddingSlidingPaneLayout 另外在官方的不同屏幕尺寸匹配里设定了窗户尺寸等级规范例如
Compact: 普通手机设备宽度 600dpMedium折叠屏或平板的竖屏600dp 宽度 840dpExpanded展开屏幕平板或平板电脑等宽度 840dp 当然还有基于高度去判断的但是大多数 App 可以通过仅考虑宽度窗口大小类别来构建响应式 UI
Compose
其实 Compose 不必多说在折叠屏适配上响应式布局本身就具有先天优势配合 Jetpack WindowManager API 提供的当前的屏幕参数就可以很灵活地达到适配不同 UI 效果。
例如 Compose 可以使用 material3-window-size-class 库然后利用 calculateWindowSizeClass() 计算当前窗口的 WindowSizeClass 从而改变 UI 的布局
import androidx.activity.compose.setContent
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClassclass MyActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {// Calculate the window size class for the activitys current window. If the window// size changes, for example when the device is rotated, the value returned by// calculateSizeClass will also change.val windowSizeClass calculateWindowSizeClass(this)// Perform logic on the window size class to decide whether to use a nav rail.val useNavRail windowSizeClass.widthSizeClass WindowWidthSizeClass.Compact// MyScreen knows nothing about window size classes, and performs logic based on a// Boolean flag.MyScreen(useNavRail useNavRail)}}
}另外还可以通过 com.google.accompanist:accompanist-adaptive 的 TwoPane 进行适配。
TwoPane 提供了两个固定的槽位两个槽位的默认位置由 TwoPaneStrategy 驱动它可以决定将两个槽位水平或垂直排列并可配置它们之间的间隔。 更多可见https://github.com/google/accompanist/tree/3810fe1182cf52c6660787ae3226dfb7f5ad372a/sample/src/main/java/com/google/accompanist/sample/adaptive 不同场景 Compose 还可以使用 FlowLayout 适配折叠变化 FlowLayout 包含 FlowRow 和 FlowColumn 当一行或一列放不下里边的内容时会自动换行这在折叠屏展开和收缩场景也非常实用。 关于 Compose 适配折叠屏 Demo 还可以参考 https://github.com/android/compose-samples/tree/main/JetNews Activity Embedding
Activity Embedding 就是通过在两个 Activity 或同一 Activity 的两个实例之间拆分窗口来优化大屏幕的支持。
理论上 Activity Embedding 不需要代码重构可以通过创建 XML 配置文件或进行 Jetpack WindowManager API 调用来确定 App 如何显示其 Activity并排或堆叠 。 Activity Embedding 默认会自动维护对小屏幕的支持当应用位于小屏幕设备上时Activity 会一个一个地堆叠在另一个之上在大屏幕上Activity 会展开并排显示。
在这个基础上它可以适应设备方向的变化并在可折叠设备上无缝工作在设备折叠或展开时堆叠被拆开的 Activity例如在聊天列表和聊天详情页面进行拆分和堆叠。 无论是 Android 12LAPI 32以上的大屏设备还是更早期折叠屏平台版本的设备Jetpack WindowManager 都能帮助构建 Activity Embedding 多窗格布局这种基于多个 Activity 而非 fragment 或基于视图的布局如 SlidingPaneLayout的方式可以最简单提供大屏幕用户体验而无需重构源代码。 一个常见的示例是列表-详情分屏为了确保高质量的呈现系统先启动列表 Activity然后应用立即启动详情 Activity过渡系统等到这两个 Activity 都绘制完成后再将它们一起显示出来对用户来说这两个 Activity 是作为一个页面启动。
目前大多数运行 Android 12LAPI 32及更高版本的大屏幕设备都支持 Activity Embedding。 使用 Jetpack WindowManager 管理和配置 Activity Embedding 其实相当灵活可以预先配置 XML 规则或者直接通过 API 进行管理配置对于 XML 配置文件中定义的规则设置以下属性
splitRatio设置容器比例。该值为开区间 (0.0, 1.0) 内的浮点数。splitLayoutDirection指定分割容器相对于彼此的布局方式。值包括 ltr 左到右rtl 右到左localeltr 或 rtl 由语言环境设置决定 可以看到 Jetpack WindowManager 十分丰富且灵活的配置支持而不是单纯简单的对 Activity 进行平均分割甚至你还可以配置一个空白 Placeholder 来进行占位显示。
使用 Activity Embedding 你需要依赖 implementation androidx.window:window:xxx 然后将该 android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED 属性添加到应用清单文件的 application 中并将值设置为 true
manifest xmlns:androidhttp://schemas.android.com/apk/res/androidapplicationpropertyandroid:nameandroid.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLEDandroid:valuetrue //application
/manifest之后就可以通过 xml 创建各种 Split Rule 或者 WindowManager API 创建 Split Rule 然后调用。
!-- main_split_config.xml --resourcesxmlns:windowhttp://schemas.android.com/apk/res-auto!-- Define a split for the named activities. --SplitPairRulewindow:splitRatio0.33window:splitLayoutDirectionlocalewindow:splitMinWidthDp840window:splitMaxAspectRatioInPortraitalwaysAllowwindow:finishPrimaryWithSecondaryneverwindow:finishSecondaryWithPrimaryalwayswindow:clearTopfalseSplitPairFilterwindow:primaryActivityName.ListActivitywindow:secondaryActivityName.DetailActivity//SplitPairRule!-- Specify a placeholder for the secondary container when content isnot available. --SplitPlaceholderRulewindow:placeholderActivityName.PlaceholderActivitywindow:splitRatio0.33window:splitLayoutDirectionlocalewindow:splitMinWidthDp840window:splitMaxAspectRatioInPortraitalwaysAllowwindow:stickyPlaceholderfalseActivityFilterwindow:activityName.ListActivity//SplitPlaceholderRule!-- Define activities that should never be part of a split. Note: Takesprecedence over other split rules for the activity named in therule. --ActivityRulewindow:alwaysExpandtrueActivityFilterwindow:activityName.ExpandedActivity//ActivityRule/resources更多可见https://developer.android.com/guide/topics/large-screens/activity-embedding SlidingPaneLayout
SlidingPaneLayout 支持在大屏幕设备并排显示两个窗格同时还会自动进行调整在手机等小屏幕设备只显示一个窗格所以在可折叠场景下也十分实用。 SlidingPaneLayout 会根据两个窗格的宽度来确定是否并排显示这些窗格例如
如果测量后发现列表窗格的最小尺寸为 200dp而详细信息窗格需要 400dp那么只要可用宽度不小于 600dpSlidingPaneLayout 就会自动并排显示两个窗格如果子视图的总宽度超过了 SlidingPaneLayout 中的可用宽度这些视图就会重叠在一起。 如果视图没有重叠那么 SlidingPaneLayout 支持对子视图使用布局参数 layout_weight以指定在测量结束后如何划分剩余的空间。 例如这个例子使用了 SlidingPaneLayout布局将 RecyclerView 作为其左侧窗格将 FragmentContainerView 作为其主要详细信息视图用于显示左侧窗格中的内容其实就类似前面介绍的在 Compose 里使用 TwoPane 的 UI。
!-- two_pane.xml --
androidx.slidingpanelayout.widget.SlidingPaneLayoutxmlns:androidhttp://schemas.android.com/apk/res/androidandroid:idid/sliding_pane_layoutandroid:layout_widthmatch_parentandroid:layout_heightmatch_parent!-- The first child view becomes the left pane. When the combineddesired width (expressed using android:layout_width) wouldnot fit on-screen at once, the right pane is permitted tooverlap the left. --androidx.recyclerview.widget.RecyclerViewandroid:idid/list_paneandroid:layout_width280dpandroid:layout_heightmatch_parentandroid:layout_gravitystart/!-- The second child becomes the right (content) pane. In thisexample, android:layout_weight is used to expand this detail paneto consume leftover available space when thethe entire window is wide enough to fit both the left and right pane.--androidx.fragment.app.FragmentContainerViewandroid:idid/detail_containerandroid:layout_width300dpandroid:layout_weight1android:layout_heightmatch_parentandroid:background#ff333333android:namecom.example.SelectAnItemFragment /
/androidx.slidingpanelayout.widget.SlidingPaneLayout另外 SlidingPaneLayout 还可以和 Navigation 配合管理 Fragment 事物并且它现在还会识别和适应折叠和铰链状态例如 使用的设备带有遮挡部分屏幕的铰链它会自动将 App 的内容放置在任一侧。 SlidingPaneLayout 还引入了锁定模式支持在窗格重叠时控制滑动行为例如 为了防止用户滑到空窗格需要点击击列表项才能加载有关该窗格的信息但允许他们滑回到列表在有空间并排显示两个视图的可折叠设备或平板电脑上锁定模式将被忽略。 更多可见 https://developer.android.com/guide/topics/ui/layout/twopane?hlzh-cn 自定义适配
除了官方的适配方案也许我们还需更灵活的自定义适配方案那么首先第一件事就是我们需要知道如何识别折叠屏。
识别折叠屏 还是前面提到的 Jetpack WindowManager Jetpack WindowManager 的 FoldingFeature 提供了有关可折叠显示器的信息的类型包括
state设备的折叠状态FLAT 完全打开 或 HALF_OPENED 处于打开和关闭状态之间的中间位置orientation折叠或铰链的方向HORIZONTAL 或者 VERTICALocclusionType折叠或铰链是否隐藏了部分显示屏NONE 不遮挡或者 FULL 遮挡isSeparating折叠或铰链是否创建两个显示区域true半开/双屏 或 false
在 Android 11 官方还提供了读取折叠角度的支持新增的类型 TYPE_HINGE_ANGLE 支持以及新的 SensorEvent SensorEvent 可以监控合页角度并提供设备的两部分之间的角度测量值
sensorManager getSystemService(Context.SENSOR_SERVICE) as SensorManagerhingeAngleSensor sensorManager?.getDefaultSensor(Sensor.TYPE_HINGE_ANGLE)而关于折叠屏的姿态我们可以通过 Jetpack WindowManager 的 API 来实现 设备处于 TableTop 模式屏幕半开并且铰链处于水平方向 fun isTableTopMode(foldFeature: FoldingFeature) foldFeature.isSeparating foldFeature.orientation FoldingFeature.Orientation.HORIZONTAL设备处于 Book 模式屏幕半开并且铰链处于垂直方向 fun isBookMode(foldFeature: FoldingFeature) foldFeature.isSeparating foldFeature.orientation FoldingFeature.Orientation.VERTICAL例如 Google Duo team 就通过 Jetpack WindowManager 识别折叠屏状态然后根据展开状态在播放过程调整界面 UI。 简单介绍一下就是在初始化时通过 WindowManager 库获取 FlowWindowLayoutInfo 让手机知道目前处于桌面模式以及如何获取折叠的位置 override fun onStart() {super.onStart()initializePlayer()layoutUpdatesJob uiScope.launch {windowInfoRepository.windowLayoutInfo.collect { newLayoutInfo -onLayoutInfoChanged(newLayoutInfo)}}}override fun onStop() {super.onStop()layoutUpdatesJob?.cancel()releasePlayer()}每次获得新的布局信息时都可以查询显示功能并检查设备在当前显示中是否有折叠或铰链
private fun onLayoutInfoChanged(newLayoutInfo: WindowLayoutInfo) {if (newLayoutInfo.displayFeatures.isEmpty()) {// The display doesnt have a display feature, we may be on a secondary,// non foldable-screen, or on the main foldable screen but in a split-view.centerPlayer()} else {newLayoutInfo.displayFeatures.filterIsInstance(FoldingFeature::class.java).firstOrNull { feature - isInTabletopMode(feature) }?.let { foldingFeature -val fold foldPosition(binding.root, foldingFeature)foldPlayer(fold)} ?: run {centerPlayer()}}}如果方向为水平且 FoldingFeature.isSeparating() 返回 true则设备可以在桌面模式下使用在这种情况下可以计算折叠的相对位置并将控件移动到对应位置否则将其移动到 0屏幕底部。 private fun centerPlayer() {ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, 0)binding.playerView.useController true // use embedded controls}private fun foldPlayer(fold: Int) {ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)binding.playerView.useController false // use custom controls}窗口大小适配
折叠设备的适配里窗口大小获取也是非常重要的一点但是其实 Android 发展至今其中一些 API 已经被弃用或者说还在被误用针对大屏幕设配的适配上因为有 Letterboxing 等情况所以其实旧的 API 已经无法满足需求。
目前已弃用且经常被误用的 Display API 有
getMetrics()getSize()getRealMetrics()getRealSize()getRectSize()getWidth()getHeight()
经常被误用的 View API 有
getWindowVisibleDisplayFrame()getLocationOnScreen
例如 Display 的 getSize() 和 getMetrics() 在 API 30 中已经被弃用取而代之的是新 WindowManager方法。 Android 12API 31弃用了 Display 的 getRealSize() 和 getRealMetrics() 更新的还有与之相关的 getMaximumWindowMetrics() 方法。 因为折叠屏和多屏幕下你的 App 实际尺寸和屏幕实际尺寸之间并不一定一致所以不能依赖物理显示尺寸来定位 UI 元素现在推荐依赖于 WindowMetrics 的 API
Platform getCurrentWindowMetrics()getMaximumWindowMetrics() Jetpack WindowMetricsCalculator#computeCurrentWindowMetrics()WindowMetricsCalculator#computeMaximumWindowMetrics()
这里的 Platform 是 Android 11API 30引入了 WindowManager 方法来提供在多窗口模式下运行的应用的边界
getCurrentWindowMetrics() 返回系统当前窗口状态对象 WindowMetricsgetMaximumWindowMetrics() 返回系统的最大窗口状态 WindowMetrics
Jetpack WindowManager 库方法 computeCurrentWindowMetrics() 和 computeMaximumWindowMetrics() 分别提供类似的功能但向后兼容到 API 14。
val windowMetrics context.createDisplayContext(display).createWindowContext(WindowManager.LayoutParams.TYPE_APPLICATION, null).getSystemService(WindowManager::class.java).maximumWindowMetrics所以通过 WindowManager 我们可以动态去管理窗口的大小变化识别折叠屏的变化状体例如在onConfigurationChanged()来配置当前窗口大小的应用布局
override fun onConfigurationChanged(newConfig: Configuration) {super.onConfigurationChanged(newConfig)val windowMetrics WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(thisMainActivity)val bounds windowMetrics.getBounds()...
}最后在窗口自定义适配上就是老生常谈的话题了例如
使用 wrap_content、match_parent 避免硬编码使用 ConstraintLayout 做根布局方便屏幕尺寸变化视图自动移动和拉伸在 App 的 AndroidManifest 里将 application 或 activity 的 android:resizeableActivity 属性设置为 true 来支持大小调整并支持响应式/自适应布局。res/layout/ 可以通过创建如 layout-w600dp 的等目录来提供自适应的布局····· 多窗口和生命周期
既然折叠屏纯在多个区域就可能存在多窗口甚至不止两个窗口这种情况下自然而然就存在生命周期适配的问题例如多个 App 同时访问 Camera 。 关于多窗口的进程可以简单介绍下 Android 7.0 支持分屏左右/上下显示两个窗口 Android 8.0 支持画中画模式此时处于画中画的 Activity 虽处于前台但处于 Paused 状态 Android 9.0 (API 28) 及以下多窗口下只有获得焦点应用处于 Resumed 状态其它可见 Activity 仍处于 Paused 状态 Android 10.0 (API 29) 多窗口模式时每个 Acttivity 全部处于Resumed状态
看到没有不同 API 级别下居然生命周期都不一样所以为解决 Android 9.0 及以下只有获得焦点应用才处于 Resume 状态问题App 端可添加下列属性手动添加开启支持多项 Resumed
meta-dataandroid:nameandroid.allow_multiple_resumed_activities android:valuetrue /也就是俗称的 Multi-resume 状态。 为了支持 Multi-resume 状态 自然就需要一个新的生命周期回调 那就是 onTopResumedActivityChanged()。
当 Activity 获得或失去顶部 Resume 位置时系统会调用该方法例如使用共享单例资源例如麦克风或摄像头时
override fun onTopResumedActivityChanged(topResumed: Boolean) {if (topResumed) {// Top resumed activity// Can be a signal to re-acquire exclusive resources} else {// No longer the top resumed activity}
}比如对于使用相机的场景针对上述封装在 Android 10API 级别 29通过CameraManager.AvailabilityCallback#onCameraAccessPrioritiesChanged() 提供了一个回调提示表明现在可能是可以尝试访问相机的时机。
这里需要注意的是使用 resizeableActivityfalse 并不能保证独占相机访问权限因为使用相机的其他 App 可能会在多方显示器上打开分屏。
所以需要 App 在收到 CameraDevice.StateCallback#onDisconnected() 回调后处理相关行为如果 onDisconnected 之后还操作 API系统就会抛出 CameraAccessException. 事实上只要通过回调做好判断其实这个「焦点」切换体验是无缝的。 在多窗口模式下Android 可能会禁用或忽略不适用于与其他 Activity 或应用共享设备屏幕的 Activity 的功能。 另外Activity 也提供了一些方法来支持多窗口模式 isInMultiWindowMode() 是否处于多窗口模式。 isInPictureInPictureMode() Activity 是否处于画中画模式。 注意画中画模式是多窗口模式的特例如果isInPictureInPictureMode() 返回 true则 isInMultiWindowMode() 也会返回 true。 onMultiWindowModeChanged() Activity 进入或退出多窗口模式时系统都会调用此方法。 如果 Activity 正在进入多窗口模式则系统向该方法传递一个值 true如果 Activity 正在离开多窗口模式则系统向该方法传递一个值 false。 onPictureInPictureModeChanged() Activity 进入或退出画中画模式时系统都会调用此方法。 如果 Activity 正在进入画中画模式则系统向该方法传递一个 true 值如果 Activity 正在离开画中画模式则系统向该方法传递一个 false 值。
Fragment 同样提供了类似方式如 Fragment.onMultiWindowModeChanged() 。
Flutter
3.13 开始 Flutter 也添加了一个新的 API 来匹配显示器的各种属性 #41685其中新的 FlutterView.display 返回一个 Display 对象Display 对象会报告显示器的物理尺寸、设备像素比和刷新率 overridevoid didChangeMetrics() {final ui.Display? display _display;if (display null) {return;}if (display.size.width / display.devicePixelRatio kOrientationLockBreakpoint) {SystemChrome.setPreferredOrientations(DeviceOrientation[DeviceOrientation.portraitUp,]);} else {SystemChrome.setPreferredOrientations(DeviceOrientation[]);}}
这个新 API 的主要目的是前面提到过的内容因为如果一旦进入了 Letterboxing 模式 Flutter 的 MediaQuery 可能就会无法获取到完整的 avalalbe 屏幕尺寸所以新的 API 就是提供折叠变化后的真实尺寸给开发者适配的空间。
另外Flutter 上关于支持多个显示器尺寸的支持还在同步 #125938 、#125939 感兴趣的也可以关注一下。
最后
能看到这里的都是很有耐心的同志本次调研的涉及的内容较多覆盖知识点也有点广有的可能不够深入大体还是提供了方向和思路主要涉及
兼容的 Letterboxing 模式表现resizeableActivity 等配置的不同行为Compose /Activity Embedding /SlidingPaneLayout 的适配方案折叠屏的判断、窗口适配和生命周期兼容Flutter API
我相信还有很多的 App 没有计划对折叠屏做适配毕竟「又不是不能用」但是了解完本篇至少可以给你提供一些底气至少看起来如果真要适配也不是什么做不到的事情。
如果你还有什么想说的欢迎留言评论交流。