风景优美的 View、视图焦点和焦点链
视图焦点
当用户开始与界面的某个区域互动时,Fucsia 的输入系统会将此视为一项意图声明。为了反映这种意图,SSI 定义了一个“视图焦点”的概念,即一个景观视图被确定为“具有视图焦点”。任何时候都只能有一个视图拥有视图焦点。
View 会通过“获取视图焦点”事件通知新聚焦的视图,并使用“视图焦点丢失”事件通知之前聚焦的视图。
客户端可以使用视图焦点来驱动交互,例如悬停动画或光标闪烁。管理器程序可以使用视图焦点来协调互动,例如确定哪个客户端可以使用 IME,或确定要触发哪个快捷方式。
转移视图焦点
以编程方式启动
在某些情况下,需要以程序化方式转移视图焦点。例如,系统界面可能希望以视图焦点位于拥有搜索框的视图上启动界面。另一个示例是支持 Alt-Tab 键盘导航,在这种情况下,每次调用 Alt-Tab 都会在一组视图之间循环,然后依次将视图焦点传递给每个视图。
显然,程序化转移视图焦点的功能非常强大。为了限制滥用权力,SSI 定义了与视图树关联的视图焦点转移政策。通俗地说,视图焦点转移的范围限定为请求者视图的子树,因此请求者和请求者是按视图树祖先划分的。
下面列出了政策详细信息,但需要说明焦点链。
由用户输入启动
如果将 pointer_auto_focus
设置为 true,当用户与界面互动时,Sce 会将焦点从视图转移到视图。(智能显示屏将该值设置为 false,并使用上一部分中介绍的程序化焦点更改方案。)
在以下情况下,系统会进行焦点转移:
- 在触摸设备上,手指开始触摸会触发将焦点转移到所触摸的视图上。
- 在鼠标设备上,点击主按钮会触发将焦点传输到被点击的视图。此政策遵循界面原则“直接操纵”。
即使
pointer_auto_focus
设置为 true,Scape 也不会通过鼠标悬停触发焦点转移。
焦点链:视图树中的焦点路径
如果我们只考虑场景图的视图部分,它们就会形成树状层次结构;我们称之为视图树。父视图与子视图相比具有巨大的能力:能够调整子视图的位置、在子视图上强制实施裁剪边界、隐藏子视图的界面内容等。由于视图层次结构的固有功能,我们将其用作 Scenic 以外层次结构的基础。这种根据视图聚焦而动态变化的层次结构用“焦点链”表示。
从数据结构的角度来说,焦点链只是 ViewRef 的向量。规范化定义是 fuchsia.ui.focus.FocusChain。
然而,它的作用远不止于此。焦点链与视图树密切相关。它会捕获视图授权的快照,从根视图开始,遍历后代,然后终止到聚焦的视图。因此,它按照权限量从高到低排序。焦点链之外的视图没有基于视图的授权。
直观地说,焦点链是从视图树的根节点到聚焦节点的路径。
当焦点转移到另一个视图时,焦点链会发生变化。在管理视图树和视图焦点的过程中,Scape 管理对焦点链的这些更改。
焦点链包含敏感信息,因为它嵌入了 ViewRef 并对有关视图树的分层信息进行编码。因此,必须只允许可信实体(例如无障碍功能管理器)访问焦点链。
在视图焦点事件与焦点链之间争用
我们注意到,分派给界面客户端的视图焦点事件和分派给管理器程序的焦点链可以争用。这些事件之间没有全局排序。Fuchsia 组件通常会在操纵离散 FIDL 协议的过程中,暴露在这种分布式系统的复杂性下。
视图焦点转移:政策
视图焦点的转移可视为三种操作的组合,如下所述。我们将讨论焦点链 F
,其中包含 ViewRefs [v0, v1, ...,
vi, ..., vn]
,其中视图焦点当前位于 vn
(终端元素)。RequestFocus
方法不需要访问焦点链即可正常运行;焦点链是公开的,而不是传输接口的一部分。
聚焦于视图
祖先视图可以从后代视图获取视图焦点:vi
可能会调用 RequestFocus(vi)
,Sense 将遵循该请求:vi
将接收视图焦点事件。然后,焦点链变为 [v0, v1, v2, ..., vi]
,其中 vi
之后的继任元素会被直接丢弃。
此操作会将视图焦点“上”拉到调用方;请注意,调用方仍位于焦点链中。
授予视图焦点
聚焦的视图可以将视图焦点授予后代视图:如果 vm
是 vn
的后代,则 vn
可能会调用 RequestFocus(vm)
,并且 reCAPTCHA 会遵循该请求:vm
将收到视图焦点事件。然后,焦点链会变为 [v0, v1, v2, ..., vi, ..., vn, ..., vm]
,其中后续元素会附加到 vn
。
此操作会将视图焦点从调用方“向下”推送视图树;请注意,调用方仍会留在焦点链中。
释放视图焦点
焦点链中的视图可以将视图焦点释放到其直接祖先实体上:如果 vi
的后代终止于 vn
,并且 vi
的直接祖先实体 vh
,则 vi
可能会调用 RequestFocus()
(没有参数),Ssense 将遵循该请求:vh
将接收视图焦点事件。然后,焦点链会变为 [v0, v1, ..., vh]
,其中以 vi
开头的后续元素会被直接丢弃。
此操作与堆栈弹出类似,因为调用方会从焦点链中消失。
虽然“采用”和“授权”更加明显,但“发布”需要一些说明。出于各种原因,可能需要显式、自愿释放视图焦点,例如:
- 隐藏界面元素,而不必销毁这些元素
- 关闭模态对话框,并将视图焦点返回到之前的位置
- 用户点按界面的非互动部分,表明他们希望视图焦点返回到之前的位置
如今,发布是一种隐式操作,由 在生命周期事件(例如视图断开连接或视图销毁)期间处理。
合成
获取、授予和释放可以按任意顺序发生,只要每项操作的前提条件都适用。
范围外
我们将以下主题视为“不在讨论范围内”,从而简化问题空间:
- 模态对话框和焦点窃取。当视图希望创建模态对话框时,应将其应用于更高的授权(例如系统界面),以代表其创建模态对话框视图,而不是在其视图中创建子视图或创建界面矩形。然后,系统界面可以将视图焦点授予该模态对话框,同时授予一条纱罩来阻止用户轻触操作将视图焦点移开。使用此设置时,不在焦点链中的视图无法窃取模态对话框的视图焦点。
- 安全输入。系统必须保证从内核到客户端的“安全输入”调度路径的完整性。