UIBezierPath contains:方法无法识别线宽大于1像素的触摸
解决UIBezierPath线宽触摸检测问题
问题原因
UIBezierPath的contains(_:)方法仅判断点是否位于路径的填充区域内,而非描边区域。你当前创建的路径只是线条的中心路径,即便设置了lineWidth,路径本身的填充范围仍为这条1像素的中心线,因此只有精准点击到中心线才会触发检测。
解决方案
方法1:生成包含描边区域的路径
利用CGPath的copy(strokingWithWidth:lineCap:lineJoin:miterLimit:transform:)方法,生成一个代表描边区域的新路径,用该路径进行触摸检测:
private func hitTest(tapLocation: CGPoint){ let originalPath: UIBezierPath = path0 // 生成覆盖描边范围的路径 let strokedPath = UIBezierPath( cgPath: originalPath.cgPath.copy( strokingWithWidth: originalPath.lineWidth, lineCap: originalPath.lineCapStyle, lineJoin: originalPath.lineJoinStyle, miterLimit: originalPath.miterLimit ) ) if strokedPath.contains(tapLocation){ print("inside") } else{ print("outside") } }
方法2:直接使用CGPath的描边检测
调用CGPath的contains(_:using:transform:strokingWithWidth:lineCap:lineJoin:miterLimit:)方法,直接指定以描边模式判断点是否在范围内:
private func hitTest(tapLocation: CGPoint){ let cgPath = path0.cgPath let isInside = cgPath.contains( tapLocation, using: .evenOdd, transform: .identity, strokingWithWidth: path0.lineWidth, lineCap: path0.lineCapStyle, lineJoin: path0.lineJoinStyle, miterLimit: path0.miterLimit ) if isInside { print("inside") } else { print("outside") } }
额外优化建议
- 移除原路径代码中的
path.close():直线路径无需闭合,闭合操作会额外添加从终点回到起点的线段,可能干扰检测。 - 移除
path.stroke():你使用CAShapeLayer负责绘制,这行代码仅在draw(_:)方法中有效,当前场景下属于冗余操作。
内容的提问来源于stack exchange,提问作者Dvole
相关产品推荐
相关产品推荐

