I created a UIBezierPath but I don't know how to access the start point of it. I tried doing this:
let startPoint = path.currentPoint
The property currentPoint
gives me the last point, not the start point. The reason I need the start point is because I want to place an image at the starting point of the path.
Any ideas?
You need to drop down to CGPath
and use CGPathApply
to walk the elements. You only want the first one, but you have to look at them all.
I'm assuming that your path is well-formed, and starts with a "move." That should always be true for a UIBezierPath
(I'm not aware of any way to make it not be true.)
You'll need some help from rob mayoff's CGPath.forEach
, which is quite tricky, but with that in place it's pretty straightforward:
// rob mayoff's CGPath.foreach
extension CGPath {
func forEach(@noescape body: @convention(block) (CGPathElement) -> Void) {
typealias Body = @convention(block) (CGPathElement) -> Void
func callback(info: UnsafeMutablePointer<Void>, element: UnsafePointer<CGPathElement>) {
let body = unsafeBitCast(info, Body.self)
body(element.memory)
}
let unsafeBody = unsafeBitCast(body, UnsafeMutablePointer<Void>.self)
CGPathApply(self, unsafeBody, callback)
}
}
// Finds the first point in a path
extension UIBezierPath {
func firstPoint() -> CGPoint? {
var firstPoint: CGPoint? = nil
self.CGPath.forEach { element in
// Just want the first one, but we have to look at everything
guard firstPoint == nil else { return }
assert(element.type == .MoveToPoint, "Expected the first point to be a move")
firstPoint = element.points.memory
}
return firstPoint
}
}
In Swift 3, it's basically the same:
// rob mayoff's CGPath.foreach
extension CGPath {
func forEach( body: @convention(block) (CGPathElement) -> Void) {
typealias Body = @convention(block) (CGPathElement) -> Void
func callback(info: UnsafeMutableRawPointer?, element: UnsafePointer<CGPathElement>) {
let body = unsafeBitCast(info, to: Body.self)
body(element.pointee)
}
let unsafeBody = unsafeBitCast(body, to: UnsafeMutableRawPointer.self)
self.apply(info: unsafeBody, function: callback)
}
}
// Finds the first point in a path
extension UIBezierPath {
func firstPoint() -> CGPoint? {
var firstPoint: CGPoint? = nil
self.cgPath.forEach { element in
// Just want the first one, but we have to look at everything
guard firstPoint == nil else { return }
assert(element.type == .moveToPoint, "Expected the first point to be a move")
firstPoint = element.points.pointee
}
return firstPoint
}
}
Simplest way is
-Subclass the UIBezierPath
-Create the custom property as startPoint
-Override the moveToPoint method and set value for startPoint there
class MyBezierPath: UIBezierPath {
var startPoint :CGPoint?
override func moveToPoint(point: CGPoint) {
super.moveToPoint(point)
startPoint=point;
}
}
var myBezier = MyBezierPath()
myBezier.moveToPoint(CGPoint(x: 0, y: 0))
myBezier.addLineToPoint(CGPoint(x: 100, y: 0))
myBezier.addLineToPoint(CGPoint(x: 50, y: 100))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With