I draw a 10 point width path, but when I try to detect touches in it, UIBezierPath contains: method does only detect touches that happen at 1 pixel line and not 10 pixel line.
let path = UIBezierPath()
path.move(to: start)
path.addLine(to: end)
path.usesEvenOddFillRule = true
path.lineWidth = 10
path.lineCapStyle = .round
path.stroke()
path.close()
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.strokeColor = lineColor.cgColor
shapeLayer.lineWidth = path.lineWidth
Here is a method to detect touch:
@objc func didTapOnView(_ recognizer: UIGestureRecognizer) {
let tapLocation:CGPoint = recognizer.location(in: self)
self.hitTest(tapLocation: CGPoint(x: tapLocation.x.rounded(), y: tapLocation.y.rounded()))
}
private func hitTest(tapLocation: CGPoint){
let path: UIBezierPath = path0
print("Touch location is: (tapLocation)")
if path.contains(tapLocation){
print("inside")
} else{
print("outside")
}
}
I’m only getting touches that happen in exact 1 pixel line and not on 10 pixel line. If I don’t do rounding, no touches get detected at all.
2
Answers
It seems like your path is only a line. For a line,
contains
only returns true for points that are on that line. It does not consider the stroke width. Of course, it is almost impossible to tap exactly on a line, which is why you don’t detect any touches at all, unless you round the touch location.You can get a
CGPath
representing the stroked area of aUIBezierPath
usingcopy(strokingWithWidth:lineCap:lineJoin:miterLimit:transform:)
. Then you can usecontains
to check whether a point is inside this area.The Problem:
containsPoint: determines if a given point precisely is on the 1-pixel-wide line route in mathematics.
Due to restrictions on touch sensing and fingertip size, touches on a physical device are limited to a specific region rather than a single spot.
Resolutions:
Expand the Hit Area:
Make the unseen path bigger: Encircle your real line with an invisible UIBezierPath that has a slightly larger stroke. This unseen route serves as a touch detection hitbox.
Customized Hit Test:
Create a unique hit test method that takes the touch position and line width into account:
}