Android 的覆盖范围在递增,体验也在变得越来越好,现已有超过 2.5 亿台大屏设施搭载了 Android 零碎,包含平板电脑、可折叠设施以及 Chrome OS 设施。如何适配不同的屏幕尺寸并保障良好的体验,始终以来都是开发者的一大难题。尤其随着可折叠设施等新兴产品的涌现,适配工作也愈发迫切。本文将重点介绍 Material Design 指南中更新的相干内容,并提供一些倡议来帮忙开发者依照自适应界面的准则来构建利用,从而解决在平板电脑和可折叠设施上的适配问题。
本文将重点探讨 View 零碎中的适配,如需理解更多无关如何利用 Compose 构建大屏幕利用的信息,请参阅文章《为任意屏幕尺寸构建 Android 界面》。
如果您更喜爱通过视频理解本文内容,请点击下方:
https://www.bilibili.com/vide…
△ 折叠屏上利用设计规范
设计指南
2021 年年初,咱们在 Material Design 网站上公布了 针对大屏设施的指南文档。Android 开发者峰会 期间咱们更新了一些内容,以帮忙开发者为可折叠设施等更多其余类型的设施做好筹备。
深刻了解布局
深刻了解布局指南 介绍了布局容器的相干概念,它提供了一个整体框架,可帮忙开发者思考如何在屏幕上排列导航栏、工具栏和内容等界面元素。
△ 布局的三个次要区域
指南中的 组合局部 带您理解如何充分利用屏幕空间以保障可读性,并且以尊重用户心智模型的形式在不同的场景下正当排布重要内容和操作选项。包含适当缩放以展现更多内容,如示例中的副标题和日期,以及较小的组合技术,例如在紧凑型的布局中对内容进行视觉分组并放弃其相关性等。
△ 组合指南中波及的局部布局形式
以 Fortnightly 示例利用为例,它在平板电脑上的界面布局非常平衡,这得益于它听从了指南里对容器的倡议。而且能够看到,Fortnightly 应用了视觉分隔线 (Visual Divider) 用于分隔最新新闻,在屏幕的另一边,则利用留白和排版对不同类别的新闻报道进行分组。
△ Fortnightly 遵循指南对内容进行分隔和分组
网格零碎
当初,许多利用将屏幕视作一个大画布或单栏,以程度和垂直的形式按互相关系绘制元素,有些利用也会在一侧整体留出边距。这一做法在小屏上或者行得通,当屏幕尺寸较大时就会呈现显著的问题。网格零碎则将您的布局划分为一系列栏,从而帮忙您在标准网格中设计更具表现力的布局。在布局中应用栏式网格 (如下图),可能让大屏设施的体验出现更贴心,更组织有序的印象,使得设施和内容更天然地融为一体。
△ 栏式网格
您能够通过这些栏将屏幕划分为不同区域,用于包容相干的信息和操作,进而改善信息层次结构。如下图所示,这里分了三个区域,这些区域将依照设计者冀望用户浏览的程序,把用户的注意力吸引到这些区域对应在屏幕的次要信息片段或信息组上。最重要的一点是,栏式网格提供了一种正当的形式来思考当屏幕尺寸变大或变小时如何将内容进行重排,从而帮忙您对不同的屏幕尺寸作出统一响应。
△ 应用栏式网格将屏幕划分为三个次要区域
在本例中,三个次要区域通过重排来放弃雷同的信息层次结构,但以更加人性化的形式在小屏幕上显示。
△ 应用栏式网格在不同屏幕尺寸中对内容进行重排
记住网格零碎有助于您抉择组件行为,在不同的布局中,以对设施尺寸和场景最有意义的形式决定替换还是更改组件。例如,在大屏设施上,您可应用 Navigation rail (左侧边栏导航条) 代替 底部导航 (Bottom navigation),两者性能雷同,视觉体现形式也相似,但 Navigation rail 可能更加人性化地排布页面。手机上的全屏对话框 (Full-screen dialog) 在大屏幕上能够采纳简略对话框 (Simple dialog) 代替,以放弃用户以后操作的上下文。
△ 在大屏上应用简略对话框 (右) 代替全屏对话框 (左)
尺寸类别
请记住,替换组件时,首先要满足用户的功能性和人性化需要。找到调整界面的正确阈值,这是实现响应式界面的重要步骤。因而咱们定义了新断点值,这有助于将设施划分到预设的尺寸类别中,这些尺寸代表了市场上理论设施的尺寸。它们有助于将利用版面的原始尺寸转换为离散的标准化组,您能够据此做出更高层次的界面决策。例如,简直所有规范手机在竖屏模式下都采纳了较小 (Compact) 宽度和中等 (Medium) 高度的组合,因为广泛应用垂直滚动,对大多数利用而言,依据宽度的尺寸类别进行适配就已足够。
△ 基于宽度的尺寸类别
△ 基于高度的尺寸类
这些 尺寸类 将作为新的 API 呈现在 1.1 版 Jetpack Window Manager 库中。从 Android Studio Bumblebee 开始,咱们还以参考设施 (Reference devices) 的模式,将尺寸类别整合到工具中,在此基础上实现界面有利于放弃一致性,操作也更加简略。而且开发者不须要去查看理论物理尺寸或屏幕方向,或其余容易出错的标识。您在设计和构建不同的尺寸类别时,请想想人们会如何手持和触摸这些类别所代表的设施。关注设施的形态和尺寸,有助于您打造出更加人性化的体验。例如,在平板电脑或大屏手机上,如果不齐全调整握持姿态,人们可能很难涉及屏幕的顶部区域,因而请将重要操作和内容放在容易涉及的区域中。
标准布局
标准布局提供了一系列通用布局计划,对设计大屏幕利用十分有帮忙。第一种是列表 / 详情,或列表网格视图的简略组合,同时在开始展现内容的屏幕起始侧,设置 / 不设置导航容器。
△ 列表 / 详情布局
反对面板可用于人们须要集中精力的体验中,例如文档。在屏幕尾侧或底部增加一块面板,以便于应用工具或上下文控件。
△ 反对面板
信息流是新闻或社交类利用中的常见模式,模板采纳图块 (Tile) 的模式来吸引用户发现更多内容。这种交互与挪动手机一样——关上一项即示意关上一个新页面,但这种体验更具沉迷感,而且专为大屏幕尺寸而设计。
△ 信息流
主页横幅优先将内容排列在屏幕顶部,并在内容四周和下方设计了反对元素,这对以媒体为核心的利用来说,是十分棒的体验。
△ 主页横幅
标准布局实际
采纳响应式界面不仅仅是为不同屏幕尺寸提供并行构造,利用还要足够灵便,这样能力依据各种须要调整尺寸,例如旋转设施、多窗口模式以及折叠和非折叠姿势。因而在运行期间,利用可从一个尺寸类别过渡到另一个尺寸类别,并再次过渡回去。重要的是,不要将尺寸类别视作齐全独立的桶,利用也需保障连续性 (即不中断用户体验),所以利用状态或数据不能失落。
△ 响应式界面可依据屏幕尺寸变动而调整内容布局
构想一下,当您调整浏览器窗口大小时,如果浏览器回退了一个页面,或者重定向到另一个页面,又或者批改了历史记录,这种体验十分奇怪。因而,每个页面都应足够灵便,而且该当可能在尺寸过渡期间放弃状态不变,这个时候标准布局就能施展重要作用。针对每个页面,您能够思考一下,当屏幕尺寸变大时,能够增加什么内容。当屏幕尺寸变小时,能够删除哪些内容。而后再抉择适合的策略。这可能意味着您须要从新扫视导航图,尤其是当您目前的设计以手机为主时更应如此。
如需构建响应式界面,咱们应该优先思考界面中长驻元素的地位,例如导航元素。遵循 Material 指南,咱们能够依据宽度的尺寸类别提供代替布局,将导航调整到最方便使用的地位。例如,小屏幕采纳底部导航视图,中等屏幕采纳 Navigation rail,大屏幕采纳残缺导航视图。请大家留神,这些布局采纳的是宽度限定符 “-w”,而非最小宽度限定符 “-sw”。残余空间用于排列内容,咱们能够在这些空间利用标准布局。
列表 / 详情
对列表 / 详情而言,AndroidX 中有个名为 SlidingPaneLayout
的专用控件,应用前需为它的两个子元素指定 layout_width
,在运行期间,SlidingPaneLayout
会判断是否有足够空间同时展现两个窗格:
<SlidingPaneLayout …>
<FragmentCOntainerView
android : id=”@+id/list_pane”android : layout_width=”300dp”android : layout_weight=”1”… />
<FragmentCOntainerView
android : id=”@+id/detail_pane”android : layout_width=”360dp”android : layout_weight=”2”<SlidingPaneLayout …>
△ SlidingPaneLayout 布局示例
当屏幕空间足够,则两个窗格至多都要达到指定的宽度,残余空间可通过 layout_weight 调配,如左图所示;如果空间有余,如右图所示,则每个窗格都应用父视图的全宽,详情窗格将被滑到一边,或间接笼罩第一个窗格。
△ SlidingPaneLayout 中空间调配后果
viewModel.selectedItemFlow.collect { item ->
// 更新详情窗格的内容
detailPane.showItem(item)
// 将详细信息窗格滑动到视图中
// 如果并排搁置两个窗格
// 并不会产生实际效果
slidingPaneLayout.openPane()}
如上代码所示,您能够通过代码管制滑动窗格,当用户从列表中抉择一个我的项目,咱们从 ViewModel 的 Kotlin 流中接管到该我的项目,而后更新详情窗格的内容,并通过调用 openPane 将其滑入视图。在 Trackr 利用 中成果如下图所示:
对于如何应用 SlidingPaneLayout 实现双窗格布局的相干内容,请参阅 Android 开发者网站: 创立双窗格布局,该页面还介绍了其余内容,例如集成系统返回按钮以实现侧滑回退窗格等。
信息流
咱们能够通过信息流沉迷式地展现一个数据集,因而 RecyclerView
是非常适合的抉择,咱们能够通过扭转 RecyclerView
应用的 LayoutManager
来扭转其展示模式。LinearLayoutManager
适宜用于较小型宽度,但在中等宽度和开展型宽度场景下,页面内容则会呈现适度拉伸和变形的状况,这时改用 GridLayoutManager
,或 StaggeredGridLayoutManager
甚至 FlexBoxLayoutManager
,可能会更适合。
△ 通过更换 RecyclerView 的 LayoutManager 来扭转其展示模式
主页横幅
咱们还能够扭转单项布局,使某些项比其余项更高或更宽,以此凸显其重要性,打造更乏味的视觉效果。在主页横幅布局中,咱们强调某个特定元素,从新排布它四周的其余反对元素。当然咱们有很多办法能够实现这一点,但 ConstraintLayout 的灵活性最大,因为它提供了很多种形式来束缚子元素的尺寸,以及绝对于其余子元素的地位。在如下媒体类示例利用,它的首图限度在 16:9 的宽高比内,形容窗格占 60% 宽度,残余空间留给其余元素。约束条件能够扭转甚至还能够用 MotionLayout
设置动画,它是一个非凡的 ConstraintLayout
。
△ 主页横幅示例
对于反对面板而言,从 LinearLayout
到 ConstraintLayout
的任何布局控件,都能够当作容器来定位面板。如下图所示,咱们思考一件事,当过渡到小屏幕尺寸时,面板上的内容应该放在哪里。咱们有许多可选计划,比方应用屏幕尾侧的侧边抽屉式导航栏,或者应用上滑式底部动作条,或者应用选项菜单,甚至能够将内容齐全暗藏起来。
适配可折叠设施
可折叠设施不仅装备了更大的屏幕,它们还能够依据设施的折叠形式和用户的应用形式调整设施的方向 / 姿态。
目前有三种常见的设施状态: 折叠、未折叠和桌面模式 (悬停)。另外,咱们稍后也将看到其余实践上存在的状态,例如书本模式。
△ 折叠设施的三种常见姿势
与其余大屏幕设施一样,咱们须要多想想用户会怎么握持未折叠设施?如平板电脑,局部屏幕区域难以用大拇指涉及,用户也很难腾出整只手来自在操控屏幕。用户轻易就能涉及屏幕的底部角落,但可能无奈涉及屏幕最顶端,尤其是在竖屏模式下。这意味着如果您应用 Navigation rail 这类组件,将导航按钮居中或固定在屏幕底部,这会更便于用户的操作。
△ 大屏设施中的用户操作热区
同时,咱们还须要思考铰链地位对交互的影响。铰链会带来显著的触觉差别,甚至两个屏幕会存在物理拆散。因而,请您防止将按钮和其余重要操作项间接放在铰链区域。大多数设施上的铰链区域宽度约为 48 dp,在桌面模式下也请防止将界面元素放在铰链区域,因为在这种设施模式下,用户简直无奈应用该区域的任何性能。
△ 铰链区域
当设施从折叠模式转换到非折叠模式时,有两种次要的技术计划可用于设计布局。第一种是扩充屏幕,该计划采纳了一种简略的响应式布局,在该布局下利用会扩大内容并填充到屏幕上。通常状况下,咱们会依据后面提到的 Material 指南 来扩大栏式网格。
第二种是减少另一个页面,依据您构建的利用不同,能够采纳与列表 / 详情或者以另一个面板补充主面板性能雷同的计划。
△ 情境 1: 扩充屏幕 (图左) 情境 2: 减少页面 (图右)
在这两种状况下,依据 material.io 的指南,您须要创立一个均匀散布在铰链区域两侧的八栏网格,当增加 Navigation rail 等导航容器时,屏幕起始侧会被压缩以包容导航容器。
△ 均匀散布在铰链两侧的八栏网格 (蓝背景)
适配示例
当初咱们来看如何在运行期间利用好折叠状态。Jetpack Window Manager
库提供了相应的 API,能够检测利用窗口是否存在折叠。任何 Activity 都能够取得一个 WindowInfoRepository
实例。而后,在 Started 和 Stopped 这两种生命周期状态之间,咱们能够平安地从窗口布局信息流中收集信息。每当流发射一个值时,咱们都能够查看 displayFeature,而后有针对性地寻找 FoldingFeature。
override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
val windowInfoRepo = windowInfoRepository()
// 在 STARTED 和 STOPPED 这两种生命周期状态之间平安地从 windowInfoRepo 中收集数据
lifecycleScope.launch(Dispatchers.Main) {lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
windowInfoRepo.windowLayoutInfo.collect { info ->
for (feature in info.displayFeatures) {
val fold = feature as? FoldingFeature ?: continue
// 应用 FoldingFeature
}
}
}
}
}
△ 辨认折叠姿势
把握了折叠姿势的相干信息后,咱们能够通过一些办法来查看设施是否处于后面提及的某种姿势。在书本模式下,设施的状态为 HALF_OPENED
,且其方向为 VERTICAL
;在桌面模式下的状态为 HALF_OPENED
,且其方向为 HORIZONTAL
。
// 书本模式是半关上的垂直折叠模式
fun FoldingFeature.isBookMode() =
state == FoldingFeature.State.HALF_OPENED &&
orientation == FoldingFeature.Orientation.VERTICAL
// 桌面模式是半关上的程度折叠模式
fun FoldingFeature.isTableTopMode() =
state == FoldingFeature.State.HALF_OPENED &&
orientation == FoldingFeature.Orientation.HORIZONTAL
△ 书本模式于桌面模式的断定条件
FoldingFeature
中还蕴含窗口中的折叠地位,当折叠导致内容视图被割裂时,咱们应该及时更新布局参数。您能够做些调整,比方将反对面板置于一侧,或者在折叠的上半局部展现主页横幅。首先,咱们须要晓得内容视图在窗口中的地位,通过 getLocationInWindow
能够获取地位信息。咱们将应用这些坐标以及宽度和高度创立一个 Rect 对象,这样咱们便失去了窗口坐标空间中的视图边界。
FoldingFeature
给出了在窗口的坐标空间中的折叠边界,因而咱们能够间接查看这两个区域是否相交,如果相交,咱们能够将 featureRect 的边界转换为视图的坐标空间并将其返回。顺便说一下,如果您应用 SlidingPaneLayout
来实现列表 / 详情布局,您会主动取得对书本模式的反对。只有两个窗格都能包容进去,SlidingPaneLayout
会将窗格置于折叠姿势的另一侧。
fun getFoldBoundsInView(
foldingFeature: FoldingFeature,
view: View
): Rect? {
// 获取视图在窗口坐标空间中的边界
val viewLocation = IntArray(2)
view.getLocationInWindow(viewLocation)
val (viewX, viewY) = viewLocation
val viewRect = Rect(
left = viewX, top = viewY
right = viewX + view.width, bottom = view + view.height
)
…
// 显示性能的边界曾经在窗口的坐标空间中
// 查看 view 的边界和显示性能的边界是否相交
val featureRect = Rect(foldingFeature.bounds)
val intersects = featureRect. intersect (viewRect)
if (featureRect.isEmpty || ! intersects)
return null
}
// 将性能的边界坐标转换为 view 的坐标空间
featureRect.offset(-viewX, -viewY)
return featureRect
}
△ 获取折叠的地位信息
测试
如果您的利用存在与折叠状态相干的非凡行为,您须要为此编写单元测试。Jetpack Window Manager
外面有一条测试规定,反对在插桩测试期间模仿 FoldingFeature
。因为测试需用到视图,咱们增加了 WindowLayoutInfoPublisherRule
,以及 ActivityScenarioRule
,两者一起组成了一个测试规定链。在该测试方法中,咱们通过 activityRule
获取 Activity
,而后创立窗口个性来模仿桌面模式,构建 WindowLayoutInfo
对象并应用 publisherRule
公布该对象。之后,咱们能够应用 Espresso
和 JUnit
断言来查看 Activity
在桌面模式下是否失常运行。
private val publisherRule = WindowLayoutInfoPublisherRule()
private val activityRule = ActivityScenarioRule (MyActivity: :class.java)
@get :Rule
val testRule = RuleChain.outerRule (publisherRule) .around(activityRule)
@Test
fun testDeviceOpen_TableTop(): Unit = testScope.runBlockingTest {
activityRule.scenario.onActivity { activity ->
val feature = FoldingFeature (activity, HALF_OPENED, HORIZONTAL)
val testWindowInfo = WindowLayoutInfo.Builder( )
.setDisplayFeatures (listOf (feature))
.build()
publisherRule.overrideWindowLayoutInfo(testWindowInfo)
}
// 编写基于桌面模式的断言
}
△ 测试折叠状态
界面测试存在肯定难度,因为有些测试须在特定设施上进行。为此,Android Studio 正在减少对 Gradle 托管的虚构设施的反对。您能够应用 7.1 及以上版本的 Android Gradle 插件来体验该性能。
在利用级的 build.gradle 文件中的 testOptions 模块下,指定虚构设施配置文件,就像您平时在 Android Studio 治理和运行虚构设施那样。例如,这里应用的是 Pixel C 平板电脑镜像,接下来 Gradle 会创立可能在指定设施上执行测试的指标,甚至还能依据须要下载设施镜像。
android {
testoptions {
devices {pixelCapi30 (ManagedVirtualDevice) {
device = "Pixel C" // 平板电脑设备
apilevel = 30
systemImageSource = "aosp" // 如需 GooglePlay 服务,应用“google”abi = "x86”}
}
}
}
#Gradle target = {device name} + {build variant} + "AndroidTest"
./gradlew pixelCapi30debugAndroidTest
△ 虚构设施配置
为便于辨别哪些测试是针对哪些设施的,咱们将创立自定义注解 LargeScreenTest,并用该注解来标记测试函数。运行后面的 Gradle 命令时,咱们会为 AndroidTestRunner 增加一项参数,确保只运行具备此正文的测试。若您不应用正文,也能够应用 TestRunner 的其余过滤选项,比方运行特定类中的测试。将这些个性加以组合,咱们能够为测试设置统一运行配置。
annotation class LargeScreenTest
@RunWith(AndroidJUnit4: :class)
class MyActivityTest {
@Test @LargeScreenTest
fun largeScreenDeviceTest() {// 在平板电脑设备上测试界面}
}
# 只运行带有指定注解的测试
. /gradlew pixelCapi30debugAndroidTest \-Pandroid.testInstrumentationRunnerArguments.annotation=com.mypkg.LargeScreenTest
△ 应用自定义注解为指定设施编写测试
更多信息
除了让屏幕上的内容看起来更大之外,大屏幕还带来了一些其余机会,帮忙您的利用大放异彩。在 多窗口模式 下,您的利用能够与其余利用并排应用,除了响应式调整之外,还能够思考如何让利用在这种模式下施展更大作用,比方反对拖拽等。这种小性能能够进步用户的工作效率,用户便更乐意应用您的利用。
△ 多窗口模式成果
除了通过触摸进行交互外,大屏幕设施还反对其余交互模式。设施的屏幕尺寸越大,用户就越有可能应用键盘、手写笔、鼠标、游戏手柄或其余外接设备。如果您想进步利用在这些状况下的易用性,能够打算反对其中一些输出形式,如需理解更多详情,请参阅文章《是时候为各式设施适配欠缺的输出反对了》。
在如此多样化的硬件生态系统中,您可能很难领有各种形态和尺寸的设施,现在 Android SDK 为可折叠设施提供了模拟器图像,这些模拟器容许您随时将折叠状态更改为铰链的角度。行将推出的 Android Studio Chipmunk 也会装备可调整尺寸的模拟器,容许您自在扭转利用窗口的尺寸,每个开发者都能够在简直任何类型的设施中试用他们的利用。
△ Android Studio Chipmunk 中的可调整尺寸的模拟器
咱们也始终在 Android Studio 中开发新工具,心愿为大家开发大屏幕利用提供反对。新的 Layout Validation
工具能够在笼罩了各种尺寸类别的参考设施上预览布局,并提醒问题区域 (例如文本应用了长行),以及为不同断点举荐不同界面组件。
△ Android Studio 中的 Layout Validation
最初,咱们在 Android 开发者网站上列出了针对 大屏幕的利用品质指南,指南中的后面局部介绍的是根本兼容性预期,比方利用是否同时反对横屏和竖屏模式,前面几局部重点介绍反对各种屏幕类型和状态,并应用特定屏幕类型或状态打造不同的体验。
咱们心愿大家都可能利用明天分享的内容,并参考新的品质指南,构建出在各种屏幕尺寸下都能让用户心动的利用。
欢迎您 点击这里 向咱们提交反馈,或分享您喜爱的内容、发现的问题。您的反馈对咱们十分重要,感谢您的反对!