垂直对齐CATextLayer中的文本?

Wil*_*sch 23 iphone macos core-animation text-alignment ios

我正在开发一个我想在Mac和iOS上使用的CATextLayer.我可以控制图层中文本的垂直对齐方式吗?

在这种特殊情况下,我希望将其垂直居中 - 但有关其他垂直对齐的信息也会引起关注.

编辑:我发现了这个,但我不能让它发挥作用.

iam*_*hed 28

正确的答案,因为你已经找到,是这里的Objective-C和适用于iOS.它通过子类化CATextLayer和重写drawInContext函数来工作.

但是,使用David Hoerl的代码作为基础对代码进行了一些改进,如下所示.这些变化仅仅是重新计算文本所代表的文本的垂直位置yDiff.我用我自己的代码测试过它.

这是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 func draw(in context: CGContext) {
        let height = self.bounds.size.height
        let fontSize = self.fontSize
        let yDiff = (height-fontSize)/2 - fontSize/10

        context.saveGState()
        context.translateBy(x: 0, y: yDiff) // Use -yDiff when in non-flipped coordinates (like macOS's default)
        super.draw(in: context)
        context.restoreGState()
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您的方式适用于单行,但对于多行(isWrapped = true),您必须先计算文本的行,然后更新 `yDiff = (height-lines*fontSize)/2 - lines*fontSize/10` (2认同)

gbk*_*gbk 12

也许迟到的答案,但你可以计算文本的大小,然后设置textLayer的位置.你还需要将textLayer textAligment模式设置为"center"

CGRect labelRect = [text boundingRectWithSize:view.bounds.size options:NSStringDrawingUsesLineFragmentOrigin attributes:@{ NSFontAttributeName : [UIFont fontWithName:@"HelveticaNeue" size:17.0] } context:nil];
CATextLayer *textLayer = [CATextLayer layer];
[textLayer setString:text];
[textLayer setForegroundColor:[UIColor redColor].CGColor];
[textLayer setFrame:labelRect];
[textLayer setFont:CFBridgingRetain([UIFont fontWithName:@"HelveticaNeue" size:17.0].fontName)];
[textLayer setAlignmentMode:kCAAlignmentCenter];
[textLayer setFontSize:17.0];
textLayer.masksToBounds = YES;
textLayer.position = CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds));
[view.layer addSublayer:textLayer];
Run Code Online (Sandbox Code Playgroud)


Eni*_*nix 7

这是一个迟到的答案,但这些天我有同样的问题,并通过以下调查解决了这个问题.

垂直对齐取决于您需要绘制的文本以及您使用的字体,因此没有一种方法可以使所有情况都垂直.

但我们仍然可以计算不同情况下的垂直中点.

根据Apple 在iOS中关于文本处理,我们需要知道如何绘制文本.

例如,我正在尝试为工作日字符串进行垂直对齐:Sun,Mon,Tue,....

对于这种情况,文本的高度取决于上限高度,并且这些字符没有下降.因此,如果我们需要使这些文本与中间对齐,我们可以计算顶部字符顶部的偏移量,例如字符"S"顶部的位置.

根据下图:

图

首都角色"S"的顶部空间将是

font.ascender - font.capHeight
Run Code Online (Sandbox Code Playgroud)

首都角色"S"的底部空间将是

font.descender + font.leading
Run Code Online (Sandbox Code Playgroud)

所以我们需要将"S"从顶部移开一点:

y = (font.ascender - font.capHeight + font.descender + font.leading + font.capHeight) / 2
Run Code Online (Sandbox Code Playgroud)

这相当于:

y = (font.ascender + font.descender + font.leading) / 2
Run Code Online (Sandbox Code Playgroud)

然后我可以使文本垂直对齐中间.

结论:

  1. 如果您的文字不包含任何超过基线的字符,例如"p","j","g",并且在帽子高度的顶部没有字符,例如"f".您可以使用上面的公式使文本对齐垂直.

    y = (font.ascender + font.descender + font.leading) / 2
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如果您的文字包含基线以下的字符,例如"p","j",并且没有字符超过上限高度,例如"f".那么垂直公式将是:

    y = (font.ascender + font.descender) / 2
    
    Run Code Online (Sandbox Code Playgroud)
  3. 如果您的文字包含不包括在基线下方绘制的字符,例如"j","p",并且包括在封面高度线上方绘制的字符,例如"f".然后你会是:

    y = (font.descender + font.leading) / 2
    
    Run Code Online (Sandbox Code Playgroud)
  4. 如果文本中出现所有字符,则y等于:

    y = font.leading / 2
    
    Run Code Online (Sandbox Code Playgroud)

  • `y`是什么意思 (2认同)

Han*_*kel 6

Swift 3版本用于常规字符串和属性字符串.

class ECATextLayer: CATextLayer {
    override open func draw(in ctx: CGContext) {
        let yDiff: CGFloat
        let fontSize: CGFloat
        let height = self.bounds.height

        if let attributedString = self.string as? NSAttributedString {
            fontSize = attributedString.size().height
            yDiff = (height-fontSize)/2
        } else {
            fontSize = self.fontSize
            yDiff = (height-fontSize)/2 - fontSize/10
        }

        ctx.saveGState()
        ctx.translateBy(x: 0.0, y: yDiff)
        super.draw(in: ctx)
        ctx.restoreGState()
    }
}
Run Code Online (Sandbox Code Playgroud)


leo*_* wu 5

感谢@iamktothed,它有效。以下是 swift 3 版本:

class CXETextLayer : CATextLayer {

override init() {
    super.init()
}

override init(layer: Any) {
    super.init(layer: layer)
}

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

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

    ctx.saveGState()
    ctx.translateBy(x: 0.0, y: yDiff)
    super.draw(in: ctx)
    ctx.restoreGState()
}
}
Run Code Online (Sandbox Code Playgroud)


Wil*_*sch -3

据我所知,我的问题的答案是“不”。