开发者

Add text to CALayer

Is it possible to add a UILabel to a CALayer without subclassing and drawing it开发者_Python百科 in drawInContext:?

Thanks!


CATextLayer *label = [[CATextLayer alloc] init];
[label setFont:@"Helvetica-Bold"];
[label setFontSize:20];  
[label setFrame:validFrame];
[label setString:@"Hello"];
[label setAlignmentMode:kCAAlignmentCenter];
[label setForegroundColor:[[UIColor whiteColor] CGColor]];
[layer addSublayer:label];

[label release];


I don't think you can add a UIView subclass to a CALayer object. However if you want to draw text on a CALayer object, it can be done using the drawing functions provided in NSString UIKit additions as shown below. While my code is done in the delegate's drawLayer:inContext method, the same can be used in subclass' drawInContext: method. Is there any specific UILabel functionality that you want to leverage?

- (void) drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
  CGContextSetFillColorWithColor(ctx, [[UIColor darkTextColor] CGColor]);

  UIGraphicsPushContext(ctx);
  /*[word drawInRect:layer.bounds 
          withFont:[UIFont systemFontOfSize:32] 
     lineBreakMode:UILineBreakModeWordWrap 
         alignment:UITextAlignmentCenter];*/

  [word drawAtPoint:CGPointMake(30.0f, 30.0f) 
           forWidth:200.0f 
           withFont:[UIFont boldSystemFontOfSize:32] 
      lineBreakMode:UILineBreakModeClip];

  UIGraphicsPopContext();
}


Just to document my approach, I did it like this in Swift 4+ :

let textlayer = CATextLayer()

textlayer.frame = CGRect(x: 20, y: 20, width: 200, height: 18)
textlayer.fontSize = 12
textlayer.alignmentMode = .center
textlayer.string = stringValue
textlayer.isWrapped = true
textlayer.truncationMode = .end
textlayer.backgroundColor = UIColor.white.cgColor
textlayer.foregroundColor = UIColor.black.cgColor

caLayer.addSublayer(textlayer) // caLayer is and instance of parent CALayer 


Your UILabel already has a CALayer behind it. If you are putting together several CALayers, you can just add the UILabel's layer as a sublayer of one of those (by using its layer property).

If it's direct text drawing in a layer that you want, the UIKit NSString additions that Deepak points to are the way to go. For an example of this in action, the Core Plot framework has a Mac / iPhone platform-independent CALayer subclass which does text rendering, CPTextLayer.


Add a CATextLayer as a sublayer and set the string property. That would be easiest and you can easily use a layout manager to make it very generic.


The answers below are fine, just make sure you add otherwise you text will be blurry:

textLayer.contentsScale = UIScreen.main.scale

Final code for Swift:

let textLayer = CATextLayer()
textLayer.frame = CGRect(x: 0, y: 0, width: 60, height: 15)
textLayer.fontSize = 12
textLayer.string = "my text"
textLayer.foregroundColor = UIColor.red.cgColor
textLayer.contentsScale = UIScreen.main.scale


class MyCALayer: CALayer {

    ......

    override func draw(in ctx: CGContext) {
        UIGraphicsPushContext(ctx)
        let text = "這是一段普通的文字"
        let textAttrs: [NSAttributedString.Key: Any] = [.font: UIFont.systemFont(ofSize: 20), .foregroundColor: UIColor.blue]
        var drawPoint = CGPoint(x: 0, y: 0)
        for char in text {
            let word = NSAttributedString(string: String(char),
                                          attributes: textAttrs)
            let wordBounds = word.boundingRect(with: CGSize(width: .max, height: .max), context: nil)
            word.draw(at: drawPoint)
            drawPoint = CGPoint(x: drawPoint.x + wordBounds.width, y: drawPoint.y)
        
            let whitespace = NSAttributedString(string: " ", attributes: textAttrs)
            let whitespaceBounds = whitespace.boundingRect(with: CGSize(width: .max, height: .max), context: nil)
            whitespace.draw(at: drawPoint)
            drawPoint = CGPoint(x: drawPoint.x + whitespaceBounds.width, y: drawPoint.y)
        }
    
        UIGraphicsPopContext()
    }

    ......
}

The result

Add text to CALayer


Always remember to remove previous sublayers, if you gonna add another one, to prevent duplicating views:

if let sublayers = layer.sublayers {
    for sublayer in sublayers {
        sublayer.removeFromSuperlayer()
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜