Как нарисовать текст при использовании слоев в NSView с Swift - PullRequest
0 голосов
/ 16 октября 2019

Я использую слои в моем NSView, так как большая часть дисплея будет меняться нечасто. Это работает нормально. Сейчас я нахожусь в точке, где я хотел бы добавить текст к слою. Это не работает.

Чтобы нарисовать текст, я пытаюсь использовать код из другого ответа на , как рисовать текст на кривой . Я исследовал, и ничего, что я пробовал, не помогает. Я создал игровую площадку для демонстрации. Когда я запускаю Playground, я вижу, что код для отображения текста на самом деле вызывается, но на экране ничего не отображается. Я уверен, что у меня что-то не так, просто не знаю, что именно.

Площадка находится ниже, вместе с кодом, указанным сверху (обновлено для Swift 5, NS * по сравнению с UI *, и комментарии удалены дляразмер).

import AppKit
import PlaygroundSupport

func centreArcPerpendicular(text str: String,
                            context: CGContext,
                            radius r: CGFloat,
                            angle theta: CGFloat,
                            colour c: NSColor,
                            font: NSFont,
                            clockwise: Bool){

   let characters: [String]         = str.map { String($0) }
   let l                            = characters.count
   let attributes                   = [NSAttributedString.Key.font: font]

   var arcs: [CGFloat] = []
   var totalArc: CGFloat = 0

   for i in 0 ..< l {
      arcs                          += [chordToArc(characters[i].size(withAttributes: attributes).width, radius: r)]
      totalArc                      += arcs[i]
   }

   let direction: CGFloat           = clockwise ? -1 : 1
   let slantCorrection: CGFloat     = clockwise ? -.pi / 2 : .pi / 2

   var thetaI                       = theta - direction * totalArc / 2

   for i in 0 ..< l {
      thetaI                        += direction * arcs[i] / 2
      centre(text: characters[i],
             context: context,
             radius: r,
             angle: thetaI,
             colour: c,
             font: font,
             slantAngle: thetaI + slantCorrection)
      thetaI                        += direction * arcs[i] / 2
   }
}

func chordToArc(_ chord: CGFloat, radius: CGFloat) -> CGFloat {
   return 2 * asin(chord / (2 * radius))
}

func centre(text str: String,
            context: CGContext,
            radius r: CGFloat,
            angle theta: CGFloat,
            colour c: NSColor,
            font: NSFont,
            slantAngle: CGFloat) {
   let attributes                   = [NSAttributedString.Key.foregroundColor: c, NSAttributedString.Key.font: font]
   context.saveGState()
   context.translateBy(x: r * cos(theta), y: -(r * sin(theta)))
   context.rotate(by: -slantAngle)
   let offset                       = str.size(withAttributes: attributes)
   context.translateBy (x: -offset.width / 2, y: -offset.height / 2)
   str.draw(at: CGPoint(x: 0, y: 0), withAttributes: attributes)
   context.restoreGState()
}
class CustomView: NSView {
   let textOnCurve                 = TextOnCurve()

   override init(frame: NSRect) {
      super.init(frame: frame)
      wantsLayer                   = true
   }
   required init?(coder aDecoder: NSCoder) {
      fatalError("init(coder:) has not been implemented")
   }
   override func updateLayer() {
      let textOnCurveLayer          = CAShapeLayer()
      textOnCurveLayer.frame        = self.frame
      textOnCurveLayer.delegate     = textOnCurve
      textOnCurveLayer.setNeedsDisplay()
      layer?.addSublayer(textOnCurveLayer)
   }
}

class TextOnCurve: NSObject, CALayerDelegate {
   func draw(_ layer: CALayer, in ctx: CGContext) {
      ctx.setFillColor(.white)
      ctx.move(to: CGPoint(x: 100, y: 100))
      ctx.addLine(to: CGPoint(x: 150, y: 100))
      ctx.addLine(to: CGPoint(x: 150, y: 150))
      ctx.addLine(to: CGPoint(x: 100, y: 150))
      ctx.closePath()
      ctx.drawPath(using: .fill)

      ctx.translateBy(x: 200.0, y: 200.0)
      centreArcPerpendicular(text: "Anticlockwise",
                             context: ctx,
                             radius: 100,
                             angle: CGFloat(-.pi/2.0),
                             colour: .red,
                             font: NSFont.systemFont(ofSize: 16),
                             clockwise: false)
      centre(text: "Hello flat world",
             context: ctx,
             radius: 0,
             angle: 0 ,
             colour: .yellow,
             font: NSFont.systemFont(ofSize: 16),
             slantAngle: .pi / 4)
   }
}


let containerView = CustomView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
PlaygroundPage.current.liveView = containerView

Поле нарисовано, а текст - нет.

Если я не использую слои, то я могу рисовать текст, вызывая методы стандартного метода draw:. Таким образом, код должен работать, но что-то в использовании слоев мешает ему.

...