如何在梯形(或圆形)中绘制文本?

Vas*_*vev 6 uikit nsattributedstring uigraphicscontext swift

让我们想象一下我有一些文字:" 有些文字是梯形的. "

我有NSAttributedString扩展,它返回带有属性文本的UIImage:

extension NSAttributedString {
    func asImage() -> UIImage? {
        defer {
            UIGraphicsEndImageContext()
        }
        let size = boundingRect(with: CGSize.zero, options: [.usesLineFragmentOrigin, .truncatesLastVisibleLine], context: nil).size
        UIGraphicsBeginImageContext(size)
        draw(at: CGPoint.zero)
        return UIGraphicsGetImageFromCurrentImageContext()
    }
}
Run Code Online (Sandbox Code Playgroud)

但是这个函数在一行中返回文本,因为使用boundingRect:

------------------------------------
|Some attributed text in trapezoid.|
------------------------------------
Run Code Online (Sandbox Code Playgroud)

如果我使用自定义rect来绘制文本,那将无济于事......

UIGraphicsBeginImageContext(CGRect(x: 0, y: 0, width: 100, height: 30))
draw(at: CGPoint.zero)
Run Code Online (Sandbox Code Playgroud)

...因为文字将是矩形:

--------------
|Some attribu|
|ted text in |
|trapezoid.  |
--------------
Run Code Online (Sandbox Code Playgroud)

我需要的是在具有已知角位置(或具有已知半径的圆圈)的梯形中绘制文本.所以每个新的文本行都应该以一点偏移量开始,参见示例: 在此输入图像描述

所以我希望看到类似的东西:

---------------
\Some attribut/
 \ed text in /
  \trapezoid/
   ---------
Run Code Online (Sandbox Code Playgroud)

我怎样才能达到这个效果?

Chr*_*orr 2

您必须在此处下降到 CoreText 级别。好消息是,您将能够以您想要的任何形状绘制文本!

extension NSAttributedString {
    public func draw(in path: CGPath) {
        let context = UIGraphicsGetCurrentContext()!

        let transform = CGAffineTransform(scaleX: +1, y: -1)

        let flippedPath = CGMutablePath()
        flippedPath.addPath(path, transform: transform)

        let range = CFRange(location: 0, length: 0)
        let framesetter = CTFramesetterCreateWithAttributedString(self)
        let frame = CTFramesetterCreateFrame(framesetter, range, flippedPath, nil)

        context.saveGState()

        // Debug: fill path.
        context.setFillColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 0.5)
        context.beginPath()
        context.addPath(path)
        context.fillPath()

        context.concatenate(transform)

        CTFrameDraw(frame, context)

        context.restoreGState()
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它:

let string = NSAttributedString(string: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.")

let bounds = CGRect(x: 0, y: 0, width: 120, height: 120)

let path = CGMutablePath()
path.move(to: CGPoint(x: 10, y: 10))
path.addLine(to: CGPoint(x: 110, y: 10))
path.addLine(to: CGPoint(x: 90, y: 110))
path.addLine(to: CGPoint(x: 30, y: 110))
path.closeSubpath()

UIGraphicsBeginImageContextWithOptions(bounds.integral.size, true, 0)
defer { UIGraphicsEndImageContext() }

let context = UIGraphicsGetCurrentContext()!
context.setFillColor(UIColor.white.cgColor)
context.fill(.infinite)

string.draw(in: path)

let image = UIGraphicsGetImageFromCurrentImageContext()!
Run Code Online (Sandbox Code Playgroud)

坏消息是,这个解决方案最后并没有给你一个省略号。如果您确实想要这样,您可能需要对框架调节器给您的最后一行进行一些调整。