如何在UILongPressGestureRecognizer上实现键盘多点触摸识别?
实现多按键同时触摸识别的方案
嘿,这个需求完全可行!不过默认的UILongPressGestureRecognizer是单触点识别的,咱们得调整几个设置,再修改触摸检测的逻辑,就能实现多按键同时触发啦。下面一步步来:
1. 调整手势识别器的触点限制
首先,给你的长按手势设置支持的最大触摸数,同时把长按时长调短(默认0.5秒太长,会有明显延迟):
// 初始化手势时添加这些配置 let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleTap(_:))) longPress.minimumPressDuration = 0.01 // 接近即时响应,模拟按键手感 longPress.maximumNumberOfTouches = 8 // 按需设置,比如支持最多8个同时按键 longPress.minimumNumberOfTouches = 1 // 至少1个触摸点触发 keyboardView.addGestureRecognizer(longPress)
2. 修改handleTap方法,遍历所有触摸点
原来的逻辑只处理单个触摸位置,现在要遍历手势的所有触摸点,逐个做hitTest,然后统一管理激活的按键:
// 先在类里维护两个集合,跟踪按键状态 private var previouslyActiveKeys = Set<CAShapeLayer>() private let allKeys: [CAShapeLayer] = [] // 这里替换成你所有按键图层的数组 @objc func handleTap(_ gesture: UILongPressGestureRecognizer) { guard let keyboardView = gesture.view else { return } var currentlyActiveKeys = Set<CAShapeLayer>() // 遍历每一个触摸点,检测命中的按键图层 for touch in gesture.touches { let touchPos = touch.location(in: keyboardView) // hitTest会返回触摸点最上层的图层,判断是否是你的Keys图层 if let hitKey = keyboardView.layer.hitTest(touchPos) as? CAShapeLayer, hitKey.name == "Keys" { currentlyActiveKeys.insert(hitKey) } } // 根据手势状态处理不同逻辑 switch gesture.state { case .began, .changed: // 把上一次激活但现在没被触摸的按键恢复原状 for key in previouslyActiveKeys where !currentlyActiveKeys.contains(key) { key.fillColor = UIColor.lightGray.cgColor // 替换成你的未点亮颜色 // 这里可以添加停止该按键发声的逻辑 } // 点亮当前触摸的按键,避免重复触发发声 for key in currentlyActiveKeys where !previouslyActiveKeys.contains(key) { key.fillColor = UIColor.systemBlue.cgColor // 替换成你的点亮颜色 playSound(for: key) // 调用你的发声方法 } // 更新上一次激活的按键集合 previouslyActiveKeys = currentlyActiveKeys case .ended, .cancelled, .failed: // 所有按键恢复初始状态,停止所有发声 for key in allKeys { key.fillColor = UIColor.lightGray.cgColor } stopAllActiveSounds() // 调用你的停止发声方法 previouslyActiveKeys.removeAll() default: break } }
3. 几个关键注意点
- 图层交互问题:
CAShapeLayer默认不参与用户交互,但hitTest是基于图层的路径和层级的,只要你的按键图层的path和位置正确,就能被命中。如果有其他图层挡住按键,要调整图层的zPosition。 - 多音播放:你的发声逻辑要支持同时播放多个音效,比如用
AVAudioPlayer的多个实例,或者AVAudioEngine来管理多个音轨,避免同时触发时只有一个声音。 - 手势状态处理:一定要处理
.changed状态,因为用户触摸移动时,可能会新增或离开某些按键,这个状态能实时更新按键状态。
内容的提问来源于stack exchange,提问作者Jacob Smolowe
相关产品推荐
相关产品推荐

