作者 / Chris Banes, Android 开发者关系团队工程师
我们将在近期为大家带来一个关于 "手势导航" 的系列连载,本文是手势导航连载的第三篇,如果您希望查看前两篇文章,请点击下方链接 :
在 上一篇文章 中,我们讨论完了从边到边绘制应用内容。从这一篇文章开始我们将介绍如何处理您的应用和 Android 10 中新引入的系统交互手势之间的冲突。
首先让我们来理解一下什么是 "手势冲突 (gesture conflict)"。我们来看一个例子,比如下面这个音乐播放应用,该应用允许用户通过拖动进度条 (SeekBar) 来快进或快退当前歌曲。
那么,如何解决这个问题呢?我们准备了一张流程图帮助大家快速做出决策:
注解: 非粘性沉浸模式: 用户可以通过在系统栏上滑动来退出沉浸模式。 粘性沉浸模式: 用户可以通过在系统栏上滑动来暂时退出沉浸模式
这里我们向您进一步解释一下流程图里的内容。
问题 1: 应用需要隐藏导航栏或状态栏吗?
流程图里的第一个问题,询问您应用的主要使用场景是否需要隐藏导航和/或状态栏。所谓 "隐藏",是指让它们根本不可见。这并不意味着让您的应用实现从边到边的全屏状态。
需要隐藏的原因可能包括:
- 使用 FLAG_FULLSCREEN WindowManager 开关。注意,这个效果也可以通过 android:windowFullscreen 主题设置来实现,或者扩展一个 Theme.XXX.Fullscreen 的衍生控件。
- 使用 SYSTEM_UI_FLAG_FULLSCREEN 这个系统 UI 可见性开关。
- 使用沉浸模式中的系统 UI 可见性开关: SYSTEM_UI_FLAG_IMMERSIVE 或 SYSTEM_UI_FLAG_IMMERSIVE_STICKY 。
一般来说,游戏、视频播放器、照片应用、绘图应用等会在这个问题中回答 "是"。
问题 2: 主要的 UI 需要在交互区域内/附近使用滑动操作吗?
这个问题是在询问,应用的界面是否在手势导航交互区域内或附近包含任何需要用户滑动操作的组件。(包括在后退和返回主屏按钮区域滑动)
不少游戏通常会在此处回答 "是",因为:
- 游戏屏幕上的控件往往非常靠近屏幕左/右边缘,或靠近屏幕底部。
- 某些游戏需要在屏幕上滑动操作一个元素,而这个元素可能出现在屏幕的任何位置,例如平台动作类的游戏。
除了游戏之外,有一些常见的 UI 也可能在这里回答 "是":
- 图片裁切 UI,其中用于裁切图片的控制点可能位于屏幕左/右边缘附近。
- 绘图应用,用户可以在屏幕画布上绘图 (自然也是滑动操作)。
问题 3: 常用的视图/控件位于手势交互区域内/附近吗?
这个问题应该简单一些。注意,这个问题也包括那些占据屏幕较大区域,且包括了手势交互区域的视图/控件。比如 DrawerLayout 或尺寸较大的 ViewPager。
问题 4: 该视图/控件需要滑动拖动交互吗?
这个紧接着问题 3 。在问题 3 中回答 "是" 的视图,是否需要用户在其上滑动或拖拽?
有不少用例会在本题回答 "是": 包括前面提到的进度条、底部弹出菜单 ( Bottom Sheet ) 或者可以通过滑动打开的弹出菜单 ( PopupMenu )。
问题 5: 该视图/控件大部分位于手势交互区域内吗?
紧接着问题 4,进一步确认该视图是否完全或大部分位于手势交互区域内。
如果您的视图放置在一个可滚动操作的容器 (如 RecyclerView ) 中,那么请这么理解这个问题: 该视图是否完全或大部分位于手势交互区域中?如果用户可以将视图滚动到手势交互区域之外,则应该视为没有交互冲突。
您也许已经注意到,在流程图中多图显示控件 (ViewPager) 在此处回答 "否"。这是因为与整个视图的宽度相比,屏幕左右侧的手势交互区域宽度相对较小 (默认为每边 20dp)。一般来说手机竖持时屏幕宽度约为 360dp,也就是说,在约为 320dp 的范围内,用户的滑动操作不受影响 (占总宽度的近 90%)。即使考虑加上了内外边距的情况,用户仍然可以正常通过滑动操作来翻看里面的图片。
问题 6: 该视图/控件是否和强制系统手势交互区域重叠?
最后一个问题询问该控件是否位于系统强制手势导航交互区域内。如果您读过我们之前的文章,应该会记得 "强制系统手势交互区" 是指系统手势始终被优先处理的屏幕区域。
对 Android 10 来说,强制交互区域只有一个,那就是屏幕底部。该区域内的滑动操作能让用户返回主屏或访问最近使用的其他应用。这个强制交互区域可能会在将来的平台版本中发生变化,但现在我们只需要考虑屏幕底部即可。
出现这种重叠的常见的例子:
- 非模态的底部弹出菜单,因为这种菜单常常会在屏幕底部折叠为一个较小的视图,而且还需要滑动操作。
- 屏幕底部的水平页面切换,例如软键盘里选择不同表情包的 UI。
OK,现在我已经解释了流程图中的问题,下面我们来详细说说流程图中给出的解决方案。
解决方案 1: 无需处理手势冲突
最简单的 "解决方案" ,只需要……什么都不做!
当然,也许您还可以 (参考接下来的几种解决方案) 做点优化,但在启用了手势导航的应用中,您应该不会遇到大问题。
如果流程图为您选择了 "什么都不做" 的答案,但您依然觉得应用的使用有问题,请务必 反馈给我们 。
解决方案 2: 将该视图/控件移出手势交互区域
我们在上一篇文章有提到,可以用 Insets 区域来告知应用系统手势区域在屏幕中的位置。我们可以用来解决手势冲突的一种方法是,将出现冲突的视图移出手势导航交互区域。这对于屏幕底部附近的视图尤其重要,因为该区域是系统强制手势交互区域,并且应用无法在该区域使用热区切出 API。