iOS Swift核心图形-字符串倒置

3

当我想在CGContext中绘制一个字符串时,文本会倒置显示。

我知道这个问题已经在这里发布过了,但是没有任何解决方案适用于我。

我确实翻转了上下文:

graphContext.scaleBy(x: 1.0, y: -1.0)
graphContext.translateBy(
        x: CGFloat(0.0),
        y: CGFloat(-1.0 * graphSize.h))

我也试图对textMatrix进行相同的操作,但这对结果没有任何影响。
完整的项目源代码在这里:dropbox,屏幕截图在这里:screen shot 我不明白为什么它不能正常工作。
谢谢。
我的绘制方法:
override func draw(_ rect: CGRect) {

        let graphSize = GSize(
            w: Double(self.frame.width),
            h: Double(self.frame.height))

        rebaseAreas(graphSize: graphSize)

        graphContext = UIGraphicsGetCurrentContext()!
        graphContext.saveGState()

        // Flip the context coordinates, in iOS only
        graphContext.scaleBy(x: 1.0, y: -1.0)
        graphContext.translateBy(
            x: CGFloat(0.0),
            y: CGFloat(-1.0 * graphSize.h))


        // this has no effect, I can delete it and nothing changes
        graphContext.textMatrix = CGAffineTransform(scaleX: 2.0, y: -2.0)


        drawBackground(
            inRect: graph_drawing_rect,
            inContext: graphContext)


        drawGuidelines(
            vAxis: vAxis,
            hAxis: hAxis,
            inRect: serie_drawing_rect,
            inContext: graphContext)


        drawSerie(
            points,
            inRect: serie_drawing_rect,
            inContext: graphContext)


        drawTitle(
            inRect: graph_drawing_rect,
            inContext: graphContext)


        drawVAxisLabels(
            vAxis: vAxis,
            inRect: x_labels_drawing_rect,
            inContext: graphContext)


        drawHAxisLabels(
            hAxis: hAxis,
            inRect: y_labels_drawing_rect,
            inContext: graphContext)

        graphContext.restoreGState()
    }

我的drawTitle方法如下:
func drawTitle(
        inRect rect: GRect,
        inContext context: CGContext) {

        // saving the calling state
        context.saveGState()

        let title = titleLabelText

        let lblAttributes = [
            NSFontAttributeName: titleFont,
            NSForegroundColorAttributeName: title_font_color,
            ] as [String : Any]

        let origin = CGPoint(
            x: title_label_position.x * rect.w,
            y: title_label_position.y * rect.h)

        let drawRect = CGRect(
            origin: origin,
            size: title.size(attributes: lblAttributes))

        title.draw(
            in: drawRect,
            withAttributes: lblAttributes)

        // returning the calling state
        graphContext.restoreGState()
    }

我所做的事情是:对于你的图形上下文,我将scaleBy更改为scaleBy(1.0, 1.0),并且对于translateBy,我将其更改为translateBy(0.0, -1.0),这样就正确显示了文本。不幸的是,位置仍然看起来有些偏差,因为在我看来,这并不像一个图表,但文本是正确的。 - Eyesofbanquo
那就是问题所在。我无法同时正确获取行和文本。 - t4ncr3d3
1个回答

8
您正在使用UIKit的字符串绘制支持。UIKit将您正在使用的方法drawInRect:withAttributes:添加到NSString中。
当它绘制字符串时,UIKit会设置文本矩阵。(您可以在CGContextSetTextMatrix上设置断点来验证这一点。) 这意味着您尝试设置的textMatrix没有任何效果。
UIKit希望图形上下文的原点位于绘图区域的左上角,并且它希望y坐标向下增加。您已经翻转了y轴的方向,因此UIKit最终会倒置绘制文本。
由于您无法使用文本矩阵解决此问题,因此您必须使用变换矩阵进行修复。您需要将原点平移到应包含文本的矩形的左上角,翻转y轴,将文本绘制在原点处,然后恢复变换矩阵。
您可以在NSString上包装此方法扩展。
private extension String {

    func drawFlipped(in rect: CGRect, withAttributes attributes: [String: Any]) {
        guard let gc = UIGraphicsGetCurrentContext() else { return }
        gc.saveGState()
        defer { gc.restoreGState() }
        gc.translateBy(x: rect.origin.x, y: rect.origin.y + rect.size.height)
        gc.scaleBy(x: 1, y: -1)
        self.draw(in: CGRect(origin: .zero, size: rect.size), withAttributes: attributes)
    }

}

那么你可以使用你的扩展方法来替代draw(in:withAttributes:)。例如,这是你的drawTitle(inRect:inContext:)方法的替换代码:

func drawTitle(
    inRect rect: GRect,
    inContext context: CGContext) {

    let title = titleLabelText

    let lblAttributes = [
        NSFontAttributeName: titleFont,
        NSForegroundColorAttributeName: title_font_color,
        ] as [String : Any]

    let origin = CGPoint(
        x: title_label_position.x * rect.w,
        y: title_label_position.y * rect.h)

    let drawRect = CGRect(
        origin: origin,
        size: title.size(attributes: lblAttributes))

    title.drawFlipped(in: drawRect, withAttributes: lblAttributes)
}

结果:

已正确绘制标题的屏幕截图

请注意,我只修复了drawTitle(inRect:inContext:),所以其他所有文本仍然是倒置的。


运行良好!!!谢谢。顺便问一下,有没有另一种方法可以在不使用UIKit的情况下绘制字符串? - t4ncr3d3
UIKit在底层使用Core Text。你可以直接使用Core Text,但对于这么简单的事情,我不建议这样做。我已经编写了绘制类似图表的代码,但我只是为每个标签使用一个单独的UILabel,并且只使用Core Graphics来绘制实际的数据点/线条/柱形图等。 - rob mayoff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接