在预发布文档中,似乎没有Swift版本的CGPathApply.有没有等价物或替代品?我正在尝试获取CGPath的所有子路径,以便我可以从不同的起点重绘它.
rob*_*off 34
在Swift 3.0中,您可以这样使用CGPath.apply
:
let path: CGPath = ...
// or let path: CGMutablePath
path.apply(info: nil) { (_, elementPointer) in
let element = elementPointer.pointee
let command: String
let pointCount: Int
switch element.type {
case .moveToPoint: command = "moveTo"; pointCount = 1
case .addLineToPoint: command = "lineTo"; pointCount = 1
case .addQuadCurveToPoint: command = "quadCurveTo"; pointCount = 2
case .addCurveToPoint: command = "curveTo"; pointCount = 3
case .closeSubpath: command = "close"; pointCount = 0
}
let points = Array(UnsafeBufferPointer(start: element.points, count: pointCount))
Swift.print("\(command) \(points)")
}
Run Code Online (Sandbox Code Playgroud)
通过添加@convention(c)
,您现在可以CGPathApply
直接从Swift 调用.这是一个做必要魔术的包装器:
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)
}
print(sizeofValue(body))
let unsafeBody = unsafeBitCast(body, UnsafeMutablePointer<Void>.self)
CGPathApply(self, unsafeBody, callback)
}
}
Run Code Online (Sandbox Code Playgroud)
(注意,@convention(c)
我的代码中没有提到,但CGPathApply
在Core Graphics模块的声明中使用.)
用法示例:
let path = UIBezierPath(roundedRect: CGRectMake(0, 0, 200, 100), cornerRadius: 15)
path.CGPath.forEach { element in
switch (element.type) {
case CGPathElementType.MoveToPoint:
print("move(\(element.points[0]))")
case .AddLineToPoint:
print("line(\(element.points[0]))")
case .AddQuadCurveToPoint:
print("quadCurve(\(element.points[0]), \(element.points[1]))")
case .AddCurveToPoint:
print("curve(\(element.points[0]), \(element.points[1]), \(element.points[2]))")
case .CloseSubpath:
print("close()")
}
}
Run Code Online (Sandbox Code Playgroud)
(提示:如果您必须在 iOS 11 之前支持 iOS,请使用已接受的答案。如果您需要 iOS 11,则此答案要容易得多。)
从iOS 11 开始,Apple 就这个问题给出了官方答案:CGPath.applyWithBlock(_:)
.
这使得所有来自CGPath.apply(info:function:)
C 函数问题的肮脏技巧都变得不必要了,该问题不允许信息以通常的快速方式传入和传出函数。
以下代码允许您执行以下操作:
let pathElements = path.pathElements()
Run Code Online (Sandbox Code Playgroud)
为了能够做到这一点,复制和粘贴
import CoreGraphics
extension CGPath {
func pathElements() -> [PathElement] {
var result = [PathElement]()
self.applyWithBlock { (elementPointer) in
let element = elementPointer.pointee
switch element.type {
case .moveToPoint:
let points = Array(UnsafeBufferPointer(start: element.points, count: 1))
let el = PathElement.moveToPoint(points[0])
result.append(el)
case .addLineToPoint:
let points = Array(UnsafeBufferPointer(start: element.points, count: 1))
let el = PathElement.addLineToPoint(points[0])
result.append(el)
case .addQuadCurveToPoint:
let points = Array(UnsafeBufferPointer(start: element.points, count: 2))
let el = PathElement.addQuadCurveToPoint(points[0], points[1])
result.append(el)
case .addCurveToPoint:
let points = Array(UnsafeBufferPointer(start: element.points, count: 3))
let el = PathElement.addCurveToPoint(points[0], points[1], points[2])
result.append(el)
case .closeSubpath:
result.append(.closeSubpath)
@unknown default:
fatalError()
}
}
return result
}
}
public enum PathElement {
case moveToPoint(CGPoint)
case addLineToPoint(CGPoint)
case addQuadCurveToPoint(CGPoint, CGPoint)
case addCurveToPoint(CGPoint, CGPoint, CGPoint)
case closeSubpath
}
Run Code Online (Sandbox Code Playgroud)
或者以这段代码为例来说明如何使用CGPath.applyWithBlock(_:)
自己。
为完整起见,这是 Apple 的官方文档:https : //developer.apple.com/documentation/coregraphics/cgpath/2873218-applywithblock
自iOS 13以来,Apple 提供了更优雅的官方答案:使用SwiftUI
(即使您的 UI 不在 中SwiftUI
)
把你cgPath
变成一个SwiftUI Path
let cgPath = CGPath(ellipseIn: rect, transform: nil)
let path = Path(cgPath)
path.forEach { element in
switch element {
case .move(let to):
break
case .line(let to):
break
case .quadCurve(let to, let control):
break
case .curve(let to, let control1, let control2):
break
case .closeSubpath:
break
}
}
Run Code Online (Sandbox Code Playgroud)
变量element
是 Path.Element 类型,它是一个纯 Swift 枚举,因此甚至不需要从元素中获取值的技巧。
为了完整起见,这是苹果官方文档:https : //developer.apple.com/documentation/swiftui/path/3059547-foreach
这是Ole Begemann的精彩文章(感谢@Gouldsc!)的亮点,该文章适用于Swift 3,它允许访问组成UIBezierPath
实例的各个元素:
extension UIBezierPath {
var elements: [PathElement] {
var pathElements = [PathElement]()
withUnsafeMutablePointer(to: &pathElements) { elementsPointer in
cgPath.apply(info: elementsPointer) { (userInfo, nextElementPointer) in
let nextElement = PathElement(element: nextElementPointer.pointee)
let elementsPointer = userInfo!.assumingMemoryBound(to: [PathElement].self)
elementsPointer.pointee.append(nextElement)
}
}
return pathElements
}
}
public enum PathElement {
case moveToPoint(CGPoint)
case addLineToPoint(CGPoint)
case addQuadCurveToPoint(CGPoint, CGPoint)
case addCurveToPoint(CGPoint, CGPoint, CGPoint)
case closeSubpath
init(element: CGPathElement) {
switch element.type {
case .moveToPoint: self = .moveToPoint(element.points[0])
case .addLineToPoint: self = .addLineToPoint(element.points[0])
case .addQuadCurveToPoint: self = .addQuadCurveToPoint(element.points[0], element.points[1])
case .addCurveToPoint: self = .addCurveToPoint(element.points[0], element.points[1], element.points[2])
case .closeSubpath: self = .closeSubpath
}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4078 次 |
最近记录: |