我使用CAShapeLayer在屏幕上画一条线。在方法 touchesEnded 我想检查"线是否通过该点?"。在我的代码中,当我按下屏幕的任何部分时,方法包含将始终返回true。也许,我在 line.frame =(view?.bounds)中遇到问题!。我该如何解决? 抱歉我的英语不好。
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
let firstPosition = touch?.location(in: self)
if atPoint(firstPosition!) == lvl1 {
let firstPositionX = firstPosition?.x
let firstPositionY = frame.size.height - (firstPosition?.y)!
view?.layer.addSublayer(line)
line.lineWidth = 8
let color = #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1).cgColor
line.strokeColor = color
line.fillColor = nil
line.frame = (view?.bounds)!
path.move(to: CGPoint(x: firstPositionX!, y: firstPositionY))
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
let firstPosition = touch?.location(in: self)
if atPoint(firstPosition!) == lvl1 {
let firstPositionX = firstPosition?.x
let firstPositionY = frame.size.height - (firstPosition?.y)!
path.addLine(to: CGPoint(x: firstPositionX!, y: firstPositionY))
line.path = path.cgPath
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if line.contains(screenCenterPoint) {
print("ok")
}
}
答案 0 :(得分:5)
如果图层的边界包含该点,则func contains(_ p: CGPoint) -> Bool
的方法CAShapeLayer
会返回true
。 (see documentation)
所以你不能用它来检查行是否包含一个点。
然而,在类CGPath
中有另一个具有相同名称的方法,它返回指定的点是内部到路径。但由于你只有描边你的路径并且你没有填充内部,这种方法也不会给出所需的结果。
诀窍是使用以下方法创建路径的大纲:
let outline = path.cgPath.copy(strokingWithWidth: line.lineWidth, lineCap: .butt, lineJoin: .round, miterLimit: 0)
然后检查大纲内部是否包含screenCenterPoint
if outline.contains(screenCenterPoint) {
print("ok")
}
由于您仅在触及结束时检查包含,我认为创建路径大纲不会增加太多开销。
如果要检查实时中的包含,例如在touchesMoved
函数内,计算大纲可能会产生一些开销,因为此方法每秒调用很多次。此外,路径越长,计算轮廓所需的时间就越长。
因此,实时最好只生成最后绘制的线段的轮廓,然后检查该轮廓是否包含您的观点。
如果您想严肃地减少开销,可以编写自己的包含功能。直线点的遏制相当简单,可以简化为以下公式:
从
start
到end
的{{1}}和width
点计算:
p
dx = start.x - end.x
dy = start.y - end.y
a = dy * p.x - dx * p.y + end.x * start.y - end.y * start.x
如果符合以下情况,则该行包含点
b = hypot(dy, dx)
p
和 p位于该行的边界框中。