【HarmonyOS 7新能力|046】智慧手势工程封装:把接入逻辑放进可维护的分层结构

滑动、长按、捏合等输入看似简单,但同一轨迹在不同页面、控件和用户目标下可能代表完全不同的动作。若识别结果直接触发删除、提交或跳转,偶发误判就会变成实际损失。智慧手势的工程重点不是追求一个漂亮的识别准确率,而是把原始事件、手势候选、业务上下文、意图置信度和可撤销动作组成受控闭环。
说明:本文的
GestureInputPort、IntentResolver等为教学抽象,不是 HarmonyOS SDK 的真实接口。手势能力、设备支持、权限和 API 签名请以当前官方文档与目标 SDK 为准。
1. 区分手势、意图与动作
手势描述输入模式,例如向左滑;意图表达用户想做什么,例如查看下一项;动作才是应用执行的命令。三者分开后,同一手势可以按页面上下文映射不同意图,也可以在高风险动作前追加确认。
ts
export interface GestureCandidate {
type: 'tap' | 'longPress' | 'swipe' | 'pinch' | 'custom'
confidence: number
direction?: 'left' | 'right' | 'up' | 'down'
magnitude?: number
occurredAt: number
}
export interface IntentCandidate {
name: string
confidence: number
reversible: boolean
}
识别层不接触业务服务,动作层也不读取原始触点。
2. 四层架构建立输入边界

交互页面负责可视反馈与常规控件;手势编排层完成候选融合、冲突仲裁和动作映射;输入能力适配层统一触摸、传感或平台手势事件;手势与动作仓库保存配置、阈值和短期执行状态。
ts
export interface GestureInputPort {
subscribe(listener: (event: NormalizedInputEvent) => void): Unsubscribe
capability(): Promise<InputCapability>
}
export interface GesturePolicyStore {
policyFor(sceneId: string): Promise<GesturePolicy>
actionFor(intent: string): Promise<ActionDescriptor | undefined>
}
页面不能直接修改识别阈值,适配器也不能调用业务命令。
3. 原始事件先归一化
不同设备的坐标、采样频率和输入方式可能不同。适配层把它们转换为统一事件,带设备类别、时间戳、坐标范围和有效性标记。
ts
export interface NormalizedInputEvent {
sequenceId: string
pointerId: number
phase: 'start' | 'move' | 'end' | 'cancel'
xRatio: number
yRatio: number
pressure?: number
source: 'touch' | 'mouse' | 'pen' | 'sensor'
timestamp: number
}
无效或乱序事件在此层丢弃,业务日志不记录可还原用户行为的完整轨迹。
4. 手势识别输出候选集合
复杂轨迹可能同时符合滑动和拖拽。识别器不急于选唯一结果,而是生成带置信度的候选集合,保留时间、方向与幅度等必要特征。
ts
export interface GestureRecognitionResult {
sequenceId: string
candidates: readonly GestureCandidate[]
completed: boolean
cancelled: boolean
}
function bestCandidate(result: GestureRecognitionResult): GestureCandidate | undefined {
return [...result.candidates].sort((a, b) => b.confidence - a.confidence)[0]
}
置信度只表示识别证据,不代表业务动作可以直接执行。
5. 智慧手势意图闭环

流程从事件采样开始,经过手势识别、上下文融合和意图判断,再进行动作确认与效果反馈。低置信度、手势冲突和用户取消进入异常旁路,不强行执行。
ts
export type IntentResolution =
| { status: 'resolved'; intent: IntentCandidate }
| { status: 'ambiguous'; alternatives: readonly IntentCandidate[] }
| { status: 'ignored'; reason: string }
模糊结果可以提示用户使用显式控件,而不是反复猜测。
6. 上下文只提供必要信息
意图判断需要知道当前页面、焦点控件、是否编辑、可用动作和用户偏好,但不应读取页面全部对象。构造窄上下文,让规则可测试。
ts
export interface GestureContext {
sceneId: string
focusedControl?: string
editing: boolean
availableActions: readonly string[]
accessibilityMode: boolean
orientation: 'portrait' | 'landscape'
}
上下文快照与手势序列绑定,页面变化后旧判断不能继续执行。
7. 冲突仲裁遵守显式优先级
子组件拖拽、父容器滚动和系统返回手势可能竞争。策略表定义作用区域、方向、最小幅度、优先级与是否允许同时识别。
ts
export interface GestureRule {
id: string
sceneId: string
gestureType: GestureCandidate['type']
region?: RectRatio
priority: number
exclusive: boolean
mappedIntent: string
}
function arbitrate(matches: GestureRule[]): GestureRule | undefined {
return [...matches].sort((a, b) => b.priority - a.priority)[0]
}
系统导航边缘和无障碍操作优先级不能被普通业务手势覆盖。
8. 置信阈值按动作风险分级
浏览下一张与删除内容的风险不同。低风险、可撤销动作可以采用较低阈值并立即反馈;不可逆动作要求更高置信度与显式确认。
ts
export interface ActionDescriptor {
id: string
risk: 'low' | 'medium' | 'high'
reversible: boolean
confirmationRequired: boolean
}
export function requiredConfidence(action: ActionDescriptor): number {
if (action.risk === 'high') return 0.95
if (action.risk === 'medium') return 0.85
return 0.7
}
数值仅为结构示例,实际阈值必须经真实场景测试确定。
9. 动作执行使用命令与幂等键
识别成功后生成业务命令,包含序列 ID、上下文版本和动作参数。执行器以命令 ID 去重,避免重复回调导致动作执行两次。
ts
export interface GestureCommand {
commandId: string
sequenceId: string
actionId: string
contextRevision: number
params: Record<string, string>
}
async function executeOnce(command: GestureCommand): Promise<ActionResult> {
const known = await actionStore.find(command.commandId)
if (known) return known
return actionExecutor.execute(command)
}
执行前再次校验页面上下文仍有效,否则取消。
10. 可撤销动作先保留补偿
移动、归档、隐藏等动作可以在短时间内提供撤销。执行记录保存补偿命令和有效期;删除等不可逆操作则在执行前使用明确确认。
ts
export interface ReversibleActionRecord {
commandId: string
actionId: string
compensation: GestureCommand
undoExpiresAt: number
state: 'applied' | 'undone' | 'expired'
}
撤销按钮是可访问的普通控件,不能要求用户再做一个复杂手势才能恢复。
11. 无障碍与多输入设备兼容
智慧手势只能是增强路径,核心功能仍应提供按钮、键盘或其他可访问入口。屏幕阅读、放大模式或运动能力受限时,策略可以禁用冲突手势并增加反馈。
ts
export interface InputFallback {
actionId: string
visibleControlId: string
keyboardShortcut?: string
voiceLabel?: string
}
鼠标、触控笔和触摸的阈值分别验证,不假设轨迹特征完全相同。
12. 验收清单与总结
测试覆盖短滑、慢拖、多指、边缘手势、连续输入、页面切换、方向变化和输入取消;验证冲突仲裁稳定、低置信结果不执行、高风险动作要求确认、重复回调幂等、撤销可用。还要在无障碍模式和多种输入设备上确认核心功能有替代入口。
智慧手势的工程价值,不是替用户猜得更多,而是在明确边界内提供更自然的快捷交互。通过输入归一化、候选识别、上下文融合、风险阈值、冲突仲裁和可撤销命令,系统既能利用意图推断,也能在不确定时安全地退回显式交互。