Ios 如何设置CATextLayer文本垂直位置?

Ios 如何设置CATextLayer文本垂直位置?,ios,uilabel,calayer,catextlayer,Ios,Uilabel,Calayer,Catextlayer,我使用以下代码在我的应用程序中创建UILabel和CATextLayer - (void)viewDidLoad { [super viewDidLoad]; self.textLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 90, 20, 20)]; self.textLabel.text = @"1"; self.textLabel.font = [UIFont systemFontOfSize:12

我使用以下代码在我的应用程序中创建
UILabel
CATextLayer

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.textLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 90, 20, 20)];
    self.textLabel.text = @"1";
    self.textLabel.font = [UIFont systemFontOfSize:12];
    self.textLabel.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.textLabel];

    self.textLayer = [CATextLayer layer];
    [self.textLayer setString:@"1"];
    [self.textLayer setFont:(__bridge CFTypeRef)([UIFont systemFontOfSize:12])];
    self.textLayer.backgroundColor = [UIColor greenColor].CGColor;
    self.textLayer.frame = CGRectMake(70, 90, 50, 20);
    [self.view.layer addSublayer:self.textLayer];
}
结果是

{
    CATextLayer *label = [[CATextLayer alloc] init];
    [label setFont:@"Helvetica-Bold"];
    [label setFontSize:16];
    [label setFrame:NSMakeRect(0, 0, NSWidth(self.frame) / 2., NSHeight(self.frame))];
    [label setString:@"ON"];
    [label setAlignmentMode:kCAAlignmentCenter];

    [label setForegroundColor:[[NSColor whiteColor] CGColor]];

    _rootLayer.layoutManager = [CAConstraintLayoutManager layoutManager];
    [label addConstraint:[CAConstraint
                          constraintWithAttribute:kCAConstraintMidY
                          relativeTo:@"superlayer"
                          attribute:kCAConstraintMidY]];
    [label addConstraint:[CAConstraint
                          constraintWithAttribute:kCAConstraintMidX relativeTo:@"superlayer" attribute:kCAConstraintMidX]];
    [_rootLayer addSublayer:label];

}


红色的是
UILabel
,绿色的是
CALayer。我想知道如何在
CALayer
中垂直对齐文本,如
UILabel`所示。

根据CATextLayer的文档,没有垂直对齐文本的选项。唯一的选项是重新定位文本层,以便与标签对齐。下面是实现相同功能的代码

CGFloat offsetY = 0;
UIFont *textFont = [UIFont systemFontOfSize:14.0f];
//if system version is grater than 6
if(([[[UIDevice currentDevice] systemVersion] compare:@"6" options:NSNumericSearch] == NSOrderedDescending)){
    offsetY = (textFont.capHeight - textFont.xHeight);
}

self.textLayer = [CATextLayer layer];
self.textLayer.backgroundColor = [UIColor greenColor].CGColor;
self.textLayer.frame = CGRectMake(70, 90+offsetY, 50, 20);
[self.view.layer addSublayer:self.textLayer];
[self.textLayer setContentsScale:[UIScreen mainScreen].scale];
[self.textLayer setForegroundColor: [UIColor blackColor].CGColor];
[self.textLayer setString:@"1"];
[self.textLayer setFont:(__bridge CFTypeRef)(textFont)];
[self.textLayer setFontSize:14.0f];
结果是

{
    CATextLayer *label = [[CATextLayer alloc] init];
    [label setFont:@"Helvetica-Bold"];
    [label setFontSize:16];
    [label setFrame:NSMakeRect(0, 0, NSWidth(self.frame) / 2., NSHeight(self.frame))];
    [label setString:@"ON"];
    [label setAlignmentMode:kCAAlignmentCenter];

    [label setForegroundColor:[[NSColor whiteColor] CGColor]];

    _rootLayer.layoutManager = [CAConstraintLayoutManager layoutManager];
    [label addConstraint:[CAConstraint
                          constraintWithAttribute:kCAConstraintMidY
                          relativeTo:@"superlayer"
                          attribute:kCAConstraintMidY]];
    [label addConstraint:[CAConstraint
                          constraintWithAttribute:kCAConstraintMidX relativeTo:@"superlayer" attribute:kCAConstraintMidX]];
    [_rootLayer addSublayer:label];

}

正确答案在Objective-C中找到,适用于iOS。它通过子类化
CATextLayer
并重写
drawInContext
函数来工作

但是,我使用David Hoerl的代码作为基础,对代码进行了一些改进,如下所示。这些更改仅在重新计算文本的垂直位置时发生

以下是Swift用户的代码:

class LCTextLayer : CATextLayer {

// REF: http://lists.apple.com/archives/quartz-dev/2008/Aug/msg00016.html
// CREDIT: David Hoerl - https://github.com/dhoerl 
// USAGE: To fix the vertical alignment issue that currently exists within the CATextLayer class. Change made to the yDiff calculation.

override init!() {
    super.init()
}

override init!(layer: AnyObject!) {
    super.init(layer: layer)
}

required init(coder aDecoder: NSCoder) {
    super.init(layer: aDecoder)
}

override func drawInContext(ctx: CGContext!) {
    let height = self.bounds.size.height
    let fontSize = self.fontSize
    let yDiff = (height-fontSize)/2 - fontSize/10

    CGContextSaveGState(ctx)
    CGContextTranslateCTM(ctx, 0.0, yDiff)
    super.drawInContext(ctx)
    CGContextRestoreGState(ctx)
}
}

事实上,这对我来说很有用:

self.layer.addSublayer(textLayer)
textLayer.font = font
textLayer.fontSize = font.pointSize
textLayer.frame = CGRectMake(self.layer.bounds.origin.x, ((self.layer.bounds.height - textLayer.fontSize) / 2) - lineWidth, self.layer.bounds.width, self.layer.bounds.height)
textLayer.alignmentMode - kCAAlignmentCenter
textLayer.contentsScale = UIScreen.mainScreen().scale

线宽是我用来“框定”边界区域的宽度。这将使我的文本保持垂直和水平居中。

Swift 3版@iamkothed的答案:

class VerticallyCenteredTextLayer : CATextLayer {

    // REF: http://lists.apple.com/archives/quartz-dev/2008/Aug/msg00016.html
    // CREDIT: David Hoerl - https://github.com/dhoerl
    // USAGE: To fix the vertical alignment issue that currently exists within the CATextLayer class.

    override func draw(in ctx: CGContext) {
        let fontSize = self.fontSize
        let height = self.bounds.size.height
        let deltaY = (height-fontSize)/2 - fontSize/10

        ctx.saveGState()
        ctx.translateBy(x: 0.0, y: deltaY)
        super.draw(in: ctx)
        ctx.restoreGState()
    }
}

我在查找iOS的CAConstraint时遇到问题。这只是一个OSX类吗?@Tark这个问题不是重复的。这个问题与iOS有关。截至iOS 11,iOS还没有可用的layoutManager。macOS开发者注意:如果包含图层的视图具有传统坐标系(未翻转),则需要将deltaY乘以-1。@Bryan感谢英雄!我已经找了好几个小时了!!!这也很有道理!这在Swift 5.3中也适用于我。但是,如果文本是多行的(文字环绕),则不会将其居中。它似乎以第一行文本为中心,这让我相信它在层的中心设置了一个边界,任何包装的文本都会被向下推。要使多行(或文字包装)文本垂直居中,需要对此做些什么?我是为macOS编写的,我已经将deltaY设置为乘以-1。macOS开发人员注意:如果包含图层的视图具有传统坐标系(未翻转),则需要将yDiff乘以-1