在圆形叠加层中绘制文本

10

我正在尝试在MKMapView上绘制一些包含文本的圆形覆盖层。 我已经对MKCircleView进行了子类化,在其中放置了以下内容(基于),但文本不会显示。圆圈正确显示。(也尝试了第一个回答的解决方案,结果相同)。

-(void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context {
   [super drawMapRect:mapRect zoomScale:zoomScale inContext:context];
   NSString * t= @"XXXXX\nXXXX" ;
   UIGraphicsPushContext(context);
   CGContextSaveGState(context); 
   [[UIColor redColor] set];
   CGRect overallCGRect = [self rectForMapRect:[self.overlay boundingMapRect]];
   NSLog(@"MKC :  %lf, %lf ----> %lf , %lf ", mapRect.origin.x ,mapRect.origin.y , overallCGRect.origin.x, overallCGRect.origin.y);
   [t drawInRect:overallCGRect withFont:[UIFont fontWithName:@"Arial" size:10.0] lineBreakMode:UILineBreakModeClip alignment:UITextAlignmentCenter];
   CGContextRestoreGState(context);
   UIGraphicsPopContext();
}

当进行调试时,我会得到这些值。
MKC :  43253760.000000, 104071168.000000 ----> 1.776503 , 1.999245 
MKC :  43253760.000000, 104071168.000000 ----> -1.562442 , -2.043090

他们正常吗?我错过了什么?谢谢。

将此与下面的答案结合起来,解决了我关于如何绘制文本的问题。然而,我的文本在水平方向上居中,但在垂直方向上却绘制在我的MKCircleView的顶部。你的文本是垂直和水平居中的吗? - Diziet
我计算文本位置的方法错了。哎呀。:P - Diziet
2
如果有人需要,这是我如何将文本居中放置在圆形中,考虑到文本的宽度和高度:`CGSize size = [str sizeWithFont:[UIFont fontWithName:@"Arial" size:9] ];CGPoint center = CGPointMake(circleRect.origin.x + circleRect.size.width /2,circleRect.origin.y + circleRect.size.height /2); CGPoint textstart = CGPointMake(center.x - size.width/2, center.y - size.height /2 );` - Templar
4个回答

12
我相信您的代码可以正常工作,问题在于文字没有按比例缩放,导致看不见。
使用MKRoadWidthAtZoomScale函数基于zoomScale缩放字体大小:
[t drawInRect:overallCGRect withFont:[UIFont fontWithName:@"Arial" 
    size:(10.0 * MKRoadWidthAtZoomScale(zoomScale))] 
    lineBreakMode:UILineBreakModeClip alignment:UITextAlignmentCenter];

此外,请确保使用与底部圆形颜色不同的文本颜色。

请注意,使用 drawInRect 将导致文本被限制在圆形内部并可能被截断。如果您想始终显示所有文本,可以改用 drawAtPoint


非常感谢!现在它可以工作了 :) 我忘记考虑缩放级别。我根据文本大小计算了圆的中心和起始点,并使用drawAtPoint使其完美居中显示。 - Templar
@Templar,你能展示一下完整的代码吗?包括你在哪里以及如何使用它? - Anirudha Mahale

4

结合这里的答案并更新IOS7:

-(void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context
{
    [super drawMapRect:mapRect zoomScale:zoomScale inContext:context];

    UIGraphicsPushContext(context);
    CGContextSaveGState(context);
    [[UIColor blueColor] set];

    NSDictionary *fontAttributes = @{NSFontAttributeName:[UIFont systemFontOfSize:10.0f * MKRoadWidthAtZoomScale(zoomScale)]};
    CGSize size = [[[self overlay] title] sizeWithAttributes:fontAttributes];
    CGFloat height = ceilf(size.height);
    CGFloat width  = ceilf(size.width);

    CGRect circleRect = [self rectForMapRect:[self.overlay boundingMapRect]];
    CGPoint center = CGPointMake(circleRect.origin.x + circleRect.size.width /2, circleRect.origin.y + circleRect.size.height /2);
    CGPoint textstart = CGPointMake(center.x - width/2, center.y - height /2 );

    [[[self overlay] title] drawAtPoint:textstart withAttributes:fontAttributes];

    CGContextRestoreGState(context);
    UIGraphicsPopContext();
}

2
很可能你的文本被绘制在一个不可见的矩形中。
首先,我建议你尝试使用%f而不是%lf来打印值,因为这些值看起来很奇怪。你还应该打印出两个矩形(mapRect和overallCGRect)的.size.width和.size.height。
如果这不能帮助你得到一个合理的矩形定义,那么你可以尝试自己定义一个CGRect,比如CGRectMake(0,0,100,20),并查看文本是否被绘制。
你也可以尝试在与你的文本相同的overallCGRect中绘制一个填充矩形。

0
这是一个适用于 macOS 的 Swift 版本 - 使用自定义的 MKOverlay 和 MKOverlayRenderer。
    /// Usage
    /// Labels
    ///
    /// let label1 = makeLabel([CLLocationCoordinate2DMake(lat + self.dyW / 2.0, lon - self.dxW / 2.0),
    ///                        CLLocationCoordinate2DMake(lat + self.dyW / 2.0, lon + self.dxW / 2.0)])
    /// label1.isAbove = false
    /// label1.text = "\(yIndex+1), \(xIndex+1)"
    /// overlays.append(label1)
    /// mapView?.addOverlay(label1)
    ///
    /// let label2 = makeLabel([CLLocationCoordinate2DMake(lat - self.dyW / 2.0, lon - self.dxW / 2.0),
    ///                        CLLocationCoordinate2DMake(lat - self.dyW / 2.0, lon + self.dxW / 2.0)])
    /// label2.isAbove = true
    /// label2.text = "\((lat - self.dyW / 2.0).formatted(3)), \((lon - self.dxW / 2.0).formatted(3))"
    /// overlays.append(label2)
    /// mapView?.addOverlay(label2)
    
    class Label: MKPolyline {
        
        var text: String = "TEXT"
        var isAbove: Bool = true
        
        let textColor = NSColor.white.withAlphaComponent(0.8).cgColor
        
    }
    
    // Custom TextOverlay
    class LabelRenderer: MKOverlayRenderer {
          
        override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
            
            // Draw Text in here
    
            guard let label = overlay as? Label else {
                print("Error this is not a Label overlay !!")
                return
            }
            
            let rect = rect(for: overlay.boundingMapRect)
           
            let textSize = 400.0
            let margin = 100.0
            
            
            
            // Draw a border if required
            //let yPos        = label.isAbove ? rect.origin.y - textSize : rect.origin.y
            
            //let center      = CGPoint(x: rect.origin.x, y: yPos)
            //let drawRect = CGRect(origin: center, size: CGSize(width: width, height: textSize))
            //context.setFillColor(NSColor.cyan.withAlphaComponent(0.8).cgColor)
            //context.fill(drawRect)
            
            // Save the state because we have to flip things for drawing text
            context.saveGState()
            
            let textStart   = CGPoint(x: rect.origin.x + 100, y: label.isAbove ? (rect.origin.y + margin ) : (rect.origin.y) - textSize)
           
            context.setStrokeColor(label.textColor)
            context.setFillColor(label.textColor)
            
            context.setTextDrawingMode(.fill)
            let font = NSFont.systemFont(ofSize: textSize)
            let string = NSAttributedString(string: label.text, attributes: [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: label.textColor])
            
            context.textPosition = textStart
            context.scaleBy(x: 1.0, y: -1.0)
            
            let line = CTLineCreateWithAttributedString(string)
            CTLineDraw(line, context)
            
            // Restore the state just incase there is some other drawing required
            context.restoreGState()
            
        }
    }

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