在 Core Graphic 中绘制的线条之间创建一个居中旋转的 UILabel

Posted

技术标签:

【中文标题】在 Core Graphic 中绘制的线条之间创建一个居中旋转的 UILabel【英文标题】:Create a centered and rotated UILabels, between drawn lines in Core Graphic 【发布时间】:2020-08-26 20:35:24 【问题描述】:

我有下面的代码,画一个圆圈,里面有段:

override func draw(_ rect: CGRect) 
    super.draw(rect)
    
    if let context = UIGraphicsGetCurrentContext()
    
        let width = fmin(self.frame.size.width, self.frame.size.height)
        let offset_x = abs(width - self.frame.size.width)/2
        let offset_y = abs(width - self.frame.size.height)/2
        let padding = CGFloat(0.5)
        let radius_size = (width/2) - (padding*2)
        let circle_width = radius_size/4
        
        context.setStrokeColor(UIColor.black.cgColor)
        
        // Draw a circle
        for i in 0 ..< 4
        
            let offset = CGFloat(i) * circle_width
            
            context.strokeEllipse(in:
                    CGRect(
                        x: padding + offset + offset_x,
                        y: padding + offset + offset_y,
                        width: (radius_size - offset)*2,
                        height: (radius_size - offset)*2))
        
        
        let angles: [CGFloat] = [87.0, 112.0, 150]
        let angles2: [CGFloat] = [210.0, 250.0, 330.0]
        let center = CGPoint(x: width/2 + offset_x, y: width/2 + offset_y)
        
        for angle in angles 
            drawLine(context: context, center: center, radius: radius_size, angle: angle)
        
        
        for angle in angles2 
            drawLine(context: context, center: center, radius: radius_size * 3 / 4, angle: angle)
        
        
        context.strokePath()

    


func drawLine(context: CGContext, center: CGPoint, radius: CGFloat, angle: CGFloat) 
    context.move(to: center)
    context.addLine(to: CGPoint(x: center.x + radius * cos(angle * .pi / 180), y: center.y - radius * sin(angle * .pi / 180)))

我希望能够在 UILabel 段之间创建一个居中,并旋转到直角,我在照片编辑器中做了一个示例:

提前致谢。

【问题讨论】:

我猜你可能想尝试绘制文本而不是创建 UILabel。我认为这可能更容易。 @Max 谢谢,任何代码示例都将不胜感激。 ***.com/a/32785652/1630618 实际上,如果您使用 CATextLayer 对象,按照您显示的方式放置它们是微不足道的。 【参考方案1】:

我找到了答案:

func drawCurvedText(angle: CGFloat, text: String) 
    drawCurvedString(
      on: textView.layer,
      text: NSAttributedString(
        string: text,
        attributes: [
            NSAttributedString.Key.foregroundColor: UIColor.white,
            NSAttributedString.Key.font: UIFont.systemFont(ofSize: 15)
        ]),
      angle: -angle,
      radius: 130)
    


func drawCurvedString(on layer: CALayer, text: NSAttributedString, angle: CGFloat, radius: CGFloat) 
  var radAngle = angle.radians

  let textSize = text.boundingRect(
    with: CGSize(width: .max, height: .max),
    options: [.usesLineFragmentOrigin, .usesFontLeading],
    context: nil)
  .integral
  .size

  let perimeter: CGFloat = 2 * .pi * radius
  let textAngle: CGFloat = textSize.width / perimeter * 2 * .pi

  var textRotation: CGFloat = 0
  var textDirection: CGFloat = 0

  if angle > CGFloat(10).radians, angle < CGFloat(170).radians 
    // bottom string
    textRotation = 0.5 * .pi
    textDirection = -2 * .pi
    radAngle += textAngle / 2
   else 
    // top string
    textRotation = 1.5 * .pi
    textDirection = 2 * .pi
    radAngle -= textAngle / 2
  

  for c in 0..<text.length 
    let letter = text.attributedSubstring(from: NSRange(c..<c+1))
    let charSize = letter.boundingRect(
      with: CGSize(width: .max, height: .max),
      options: [.usesLineFragmentOrigin, .usesFontLeading],
      context: nil)
    .integral
    .size

    let letterAngle = (charSize.width / perimeter) * textDirection
    let x = radius * cos(radAngle + (letterAngle / 2))
    let y = radius * sin(radAngle + (letterAngle / 2))

    let singleChar = drawText(
      on: layer,
      text: letter,
      frame: CGRect(
        x: (layer.frame.size.width / 2) - (charSize.width / 2) + x,
        y: (layer.frame.size.height / 2) - (charSize.height / 2) + y,
        width: charSize.width,
        height: charSize.height))
    layer.addSublayer(singleChar)
    singleChar.transform = CATransform3DMakeAffineTransform(CGAffineTransform(rotationAngle: radAngle - textRotation))
    radAngle += letterAngle
  



func drawText(on layer: CALayer, text: NSAttributedString, frame: CGRect) -> CATextLayer 
  let textLayer = CATextLayer()
  textLayer.frame = frame
  textLayer.string = text
    textLayer.alignmentMode = CATextLayerAlignmentMode.center
  textLayer.contentsScale = UIScreen.main.scale
  return textLayer

【讨论】:

我在评论中建议使用文本层。

以上是关于在 Core Graphic 中绘制的线条之间创建一个居中旋转的 UILabel的主要内容,如果未能解决你的问题,请参考以下文章

ArcGIS创建点、线、面等几何图形

在d3.js中的点之间绘制线条

javascript 在元素之间绘制线条

使用 python 在打开的 cv 中使用鼠标事件绘制矩形或线条

Qt,C++ 在 2 个对象之间绘制连接线

MATLAB,填充两组数据之间的区域,一个图中的线条