
本文详解如何利用 TouchEvent.changedTouches 和 Touch.identifier 在 pinch 手势中精准判断哪根手指被抬起,适用于任意数量手指的复杂触控场景,并提供可直接复用的工具函数与实践示例。
本文详解如何利用 `touchevent.changedtouches` 和 `touch.identifier` 在 pinch 手势中精准判断哪根手指被抬起,适用于任意数量手指的复杂触控场景,并提供可直接复用的工具函数与实践示例。
在实现多指手势(如双指缩放、三指滑动等)时,一个常见但棘手的问题是:当用户用 N 根手指同时触屏后,逐步抬起其中若干根,如何准确知道哪些手指离开了?仅靠 event.touches.length 的变化无法定位具体是哪个索引(如第 0 个还是第 1 个 Touch)被移除——因为 touches 列表本身已动态更新,旧索引不再对应原始触摸点。
关键在于理解 TouchEvent 的两个核心属性:
- event.touches: 当前仍处于按下状态的所有触摸点(即“存活”手指),按任意顺序排列(不保证与起始顺序一致);
- event.changedTouches: 本次事件中状态发生变更的触摸点列表。对 touchend 事件而言,它精确包含所有刚刚抬起的手指,每个 Touch 对象均携带唯一且稳定的 identifier 字段。
✅ 正确做法:不依赖索引位置,而基于 identifier 做匹配。
每根手指在首次接触屏幕时(touchstart)会被分配一个全局唯一的 identifier(整数),该值在整个生命周期内不变,即使其他手指抬起/落下也不会重用。因此,我们应缓存初始触摸的 identifier,并在 touchend 中比对 changedTouches 中的 identifier,从而精准识别哪根手指被抬起。
以下是一个健壮的实现示例:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
// 工具函数:将 TouchList 转为数组(便于 filter/map)
const touchListToArray = (touches: TouchList): Touch[] => {
return Array.from(touches); // 更简洁的现代写法(推荐)
};
let cachedStartIdentifiers: number[] = [];
let cachedMoveIdentifiers: number[] = [];
function onStart(ev: TouchEvent) {
ev.preventDefault();
const touches = touchListToArray(ev.touches);
cachedStartIdentifiers = touches.map(t => t.identifier);
cachedMoveIdentifiers = [...cachedStartIdentifiers];
}
function onMove(ev: TouchEvent) {
ev.preventDefault();
const touches = touchListToArray(ev.touches);
cachedMoveIdentifiers = touches.map(t => t.identifier);
}
function onEnd(ev: TouchEvent) {
ev.preventDefault();
// ✅ changedTouches 包含所有本次抬起的手指
const liftedIdentifiers = touchListToArray(ev.changedTouches).map(t => t.identifier);
// 从缓存中移除已抬起的 identifier
cachedStartIdentifiers = cachedStartIdentifiers.filter(id => !liftedIdentifiers.includes(id));
cachedMoveIdentifiers = cachedMoveIdentifiers.filter(id => !liftedIdentifiers.includes(id));
console.log('剩余活跃手指 identifiers:', cachedMoveIdentifiers);
console.log('本次抬起的 identifiers:', liftedIdentifiers);
}? 重要注意事项:
立即学习“Java免费学习笔记(深入)”;
- 永远不要假设 touches 索引顺序稳定:浏览器可能因底层驱动或平台差异重新排序 touches,依赖 touches[0] 对应“第一根手指”是不可靠的;
- identifier 是唯一可靠标识符:它是触摸点的“身份证”,跨 start/move/end 事件保持一致;
- changedTouches 在 touchend 中只含抬起的手指,在 touchstart 中只含新接触的手指,在 touchmove 中含位置/状态发生变化的手指;
- 若需关联原始触摸数据(如起始坐标),建议构建 Map<number, TouchData> 缓存,以 identifier 为键存储完整信息。
总结:处理多指触控的核心范式是 “以 identifier 为中心,而非数组索引”。通过 changedTouches 获取变更集,结合 identifier 做集合运算(如 filter、includes),即可优雅支持任意数量手指的并发抬起/按下,为复杂手势识别(如旋转、缩放、多点拖拽)奠定坚实基础。

















