Swift:使用UIBezierPath绘制文本

Swift:使用UIBezierPath绘制文本,swift,core-graphics,nsattributedstring,uibezierpath,Swift,Core Graphics,Nsattributedstring,Uibezierpath,由于我在谷歌上找不到合适的答案,问题是: 我需要绘制属性字符串的形状,最好使用UIBezierPath。有什么方法可以做到这一点吗?你最好使用这样的东西。使用贝塞尔路径可能非常复杂,尤其是当您要绘制多个单词时。这将需要大量的定制工作和头痛,试图得到在正确的顺序和相同的y位置绘制线。 下面将画出您设置的任何单词 var charLayers = [CAShapeLayer]() func drawText() { for layer in self.charLayers {

由于我在谷歌上找不到合适的答案,问题是:
我需要
绘制
属性字符串的形状,最好使用
UIBezierPath
。有什么方法可以做到这一点吗?

你最好使用这样的东西。使用贝塞尔路径可能非常复杂,尤其是当您要绘制多个单词时。这将需要大量的定制工作和头痛,试图得到在正确的顺序和相同的y位置绘制线。 下面将画出您设置的任何单词

var charLayers = [CAShapeLayer]()

  func drawText() {
        for layer in self.charLayers {
            layer.removeFromSuperlayer()
        }
        let font = [NSAttributedString.Key.font: UIFont(name: fontNameHEre, size: FontSizeHere)! ]
        let attributedString = NSMutableAttributedString(string: "myStringHere", attributes: font)
        let charPaths = self.characterPaths(attributedString: attributedString, position: CGPoint(x: 255, y: 632))

        self.charLayers = charPaths.map { path -> CAShapeLayer in
            let shapeLayer = CAShapeLayer()
            shapeLayer.fillColor = UIColor.clear.cgColor
            shapeLayer.strokeColor = UIColor.black.cgColor
            shapeLayer.lineWidth = lineWidth
            shapeLayer.path = path
            return shapeLayer
        }
}
结果将是您定义的字符串。它会为你画出来的

只要在需要绘制图形的地方调用函数
drawText()

--------编辑

抱歉,忘记添加重要功能

见下文

    func characterPaths(attributedString: NSAttributedString, position: CGPoint) -> [CGPath] {

    let line = CTLineCreateWithAttributedString(attributedString)

    guard let glyphRuns = CTLineGetGlyphRuns(line) as? [CTRun] else { return []}

    var characterPaths = [CGPath]()

    for glyphRun in glyphRuns {
        guard let attributes = CTRunGetAttributes(glyphRun) as? [String:AnyObject] else { continue }
        let font = attributes[kCTFontAttributeName as String] as! CTFont

        for index in 0..<CTRunGetGlyphCount(glyphRun) {
            let glyphRange = CFRangeMake(index, 1)

            var glyph = CGGlyph()
            CTRunGetGlyphs(glyphRun, glyphRange, &glyph)

            var characterPosition = CGPoint()
            CTRunGetPositions(glyphRun, glyphRange, &characterPosition)
            characterPosition.x += position.x
            characterPosition.y += position.y

            if let glyphPath = CTFontCreatePathForGlyph(font, glyph, nil) {
                var transform = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: characterPosition.x, ty: characterPosition.y)
                if let charPath = glyphPath.copy(using: &transform) {
                    characterPaths.append(charPath)
                }
            }
        }
    }
    return characterPaths
}
func字符路径(attributedString:NSAttributedString,位置:CGPoint)->[CGPath]{
let line=CTLineCreateWithAttributedString(attributedString)
guard let glyphRuns=CTLineGetGlyphRuns(行)作为?[CTRun]else{return[]}
变量CharacterPath=[CGPath]()
对于glyphRun中的glyphRun{
guard let attributes=CtrunGetAttribute(glyphRun)作为?[String:AnyObject]其他{continue}
让font=attributes[kCTFontAttributeName作为字符串]作为!CTFont

对于0中的索引,…您最好使用这样的东西。使用贝塞尔路径可能非常复杂,尤其是当您要绘制多个单词时。如果要以正确的顺序和相同的y位置绘制直线,将需要大量自定义工作和头痛。 下面将画出您设置的任何单词

var charLayers = [CAShapeLayer]()

  func drawText() {
        for layer in self.charLayers {
            layer.removeFromSuperlayer()
        }
        let font = [NSAttributedString.Key.font: UIFont(name: fontNameHEre, size: FontSizeHere)! ]
        let attributedString = NSMutableAttributedString(string: "myStringHere", attributes: font)
        let charPaths = self.characterPaths(attributedString: attributedString, position: CGPoint(x: 255, y: 632))

        self.charLayers = charPaths.map { path -> CAShapeLayer in
            let shapeLayer = CAShapeLayer()
            shapeLayer.fillColor = UIColor.clear.cgColor
            shapeLayer.strokeColor = UIColor.black.cgColor
            shapeLayer.lineWidth = lineWidth
            shapeLayer.path = path
            return shapeLayer
        }
}
结果将是您定义的字符串。它将为您绘制

只要在需要绘制图形的地方调用函数
drawText()

--------编辑

抱歉,忘记添加重要功能

见下文

    func characterPaths(attributedString: NSAttributedString, position: CGPoint) -> [CGPath] {

    let line = CTLineCreateWithAttributedString(attributedString)

    guard let glyphRuns = CTLineGetGlyphRuns(line) as? [CTRun] else { return []}

    var characterPaths = [CGPath]()

    for glyphRun in glyphRuns {
        guard let attributes = CTRunGetAttributes(glyphRun) as? [String:AnyObject] else { continue }
        let font = attributes[kCTFontAttributeName as String] as! CTFont

        for index in 0..<CTRunGetGlyphCount(glyphRun) {
            let glyphRange = CFRangeMake(index, 1)

            var glyph = CGGlyph()
            CTRunGetGlyphs(glyphRun, glyphRange, &glyph)

            var characterPosition = CGPoint()
            CTRunGetPositions(glyphRun, glyphRange, &characterPosition)
            characterPosition.x += position.x
            characterPosition.y += position.y

            if let glyphPath = CTFontCreatePathForGlyph(font, glyph, nil) {
                var transform = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: characterPosition.x, ty: characterPosition.y)
                if let charPath = glyphPath.copy(using: &transform) {
                    characterPaths.append(charPath)
                }
            }
        }
    }
    return characterPaths
}
func字符路径(attributedString:NSAttributedString,位置:CGPoint)->[CGPath]{
let line=CTLineCreateWithAttributedString(attributedString)
guard let glyphRuns=CTLineGetGlyphRuns(行)作为?[CTRun]else{return[]}
变量CharacterPath=[CGPath]()
对于glyphRun中的glyphRun{
guard let attributes=CtrunGetAttribute(glyphRun)作为?[String:AnyObject]其他{continue}
让font=attributes[kCTFontAttributeName作为字符串]作为!CTFont

对于0中的索引,“绘制属性字符串的形状”正是任何文本元素自动执行的操作(UILabel、NSAttributeString.Draw(at:)、CTLineDraw等).所以我希望你的意思比这更具体。你打算用UIBezierPath做什么?通过核心文本从NSAttributeString到UIBezierPath是绝对可能的,但这是一项工作,如果你想处理NSAttributedString所能做的一切,那就变得相当复杂,所以如果你真的这么做了,最好能理解一下需要所有这些,或者如果一个更简单的解决方案将满足你的需要。通常CtEXTAL是最好的。我的目标是用文字和图片一起工作。我希望能够修剪它,在中间切一个圆圈,弯曲。如果你想把它当作一幅画,你不想要一个UiBiZielPress。这会使你的工作更难。你想把它渲染成一个图像和W。处理图像。修剪和剪切最好用遮罩来完成,这可以用CGContext或CATextLayer轻松完成。如果要我猜你在做什么,我猜你真的想要一个CATextLayer,因为这可以让你访问大量遮罩、剪裁和CIFilter操作。“绘制属性字符串的形状”正是任何文本元素自动执行的操作(UILabel、NSAttributeString.draw(at:)、CTLineDraw等).所以我希望你的意思比这更具体。你打算用UIBezierPath做什么?通过核心文本从NSAttributeString到UIBezierPath是绝对可能的,但这是一项工作,如果你想处理NSAttributedString所能做的一切,那就变得相当复杂,所以如果你真的这么做了,最好能理解一下需要所有这些,或者如果一个更简单的解决方案将满足你的需要。通常CtEXTAL是最好的。我的目标是用文字和图片一起工作。我希望能够修剪它,在中间切一个圆圈,弯曲。如果你想把它当作一幅画,你不想要一个UiBiZielPress。这会使你的工作更难。你想把它渲染成一个图像和W。处理图像。修剪和剪切最好用遮罩来完成,这可以用CGContext或CATextLayer轻松完成。如果要我猜你在做什么,我猜你真的想要一个CATextLayer,因为这可以让你访问大量遮罩、剪裁和CIFilter操作。什么是
self.characterPath()
?@koen sorry check updated answer这将支持足够多的NSAttributed String,在许多情况下非常有用,但请记住,它不处理很多NSAttributed String属性,特别是文本装饰(例如下划线、删除线和阴影)。什么是
self.characterPath()
?@koen sorry check updated answer这将支持足够多的NSAttributed String,在许多情况下非常有用,但请记住,它不处理很多NSAttributed String属性,特别是文本装饰(例如下划线、删除线和阴影)。