Вы можете найти это здесь в моем ответе

отаю над CATextLayer, который хочу использовать как на Mac, так и на iOS. Могу ли я контролировать вертикальное выравнивание текста в слое?

В этом конкретном случае я хочу центрировать его по вертикали, но информация о других вертикальных выравниваниях также будет интересна.

РЕДАКТИРОВАТЬ: я нашелэто, но я не могу заставить это работать.

Ответы на вопрос(10)

Если вы используете приписанную строку для установки свойств шрифта, то вы можете использовать функцию size () из NSAttributedString для вычисления высоты строки. Я думаю, что этот код также решает проблемы, описанные @Enix

class LCTextLayer: CATextLayer {

    override init() {
        super.init()
    }

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

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

    override open func draw(in ctx: CGContext) {

        if let attributedString = self.string as? NSAttributedString {

            let height = self.bounds.size.height
            let stringSize = attributedString.size()
            let yDiff = (height - stringSize.height) / 2

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

обновленный для бета-версии XCode 8. По состоянию на 1 октября 2016 г.

Шаг 1. Подкласс CATextLayer. В приведенном ниже коде я назвал подкласс «MyCATextLayer». За пределами вашего класса контроллера представления скопируйте / вставьте приведенный ниже код.

class MyCATextLayer: 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()
}

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()
   }
}

Шаг 2. Создайте CATextLabel в своем классе контроллера представления в вашем файле .swift. В примере кода я назвал подкласс «MyDopeCATextLayer».

let MyDopeCATextLayer: MyCATextLayer = MyCATextLayer()

Шаг 3. Установите новый CATextLayer с нужным текстом / цветом / границами / рамкой.

MyDopeCATextLayer.string = "Hello World"    // displayed text
MyDopeCATextLayer.foregroundColor = UIColor.purple.cgColor //color of text is purple
MyDopeCATextLayer.frame = CGRect(x: 0, y:0, width: self.frame.width, height: self.frame.height)  
MyDopeCATextLayer.font = UIFont(name: "HelveticaNeue-UltraLight", size: 5) //5 is ignored, set actual font size using  ".fontSize" (below)
MyDopeCATextLayer.fontSize = 24
MyDopeCATextLayer.alignmentMode = kCAAlignmentCenter //Horizontally centers text.  text is automatically centered vertically because it's set in subclass code
MyDopeCATextLayer.contentsScale = UIScreen.main.scale  //sets "resolution" to whatever the device is using (prevents fuzzyness/blurryness)

Шаг 4. сделано

Версия 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()
    }
}

Вот в Objective-C иработает на iOS, Это работает путем подклассаCATextLayer и переопределяяdrawInContext функция.

Тем не мение,Я сделал некоторые улучшения в коде, как показано ниже, используя код Дэвида Херла в качестве основы.изменения прийти исключительно впересчитывая вертикальную позицию текста представлен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 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)
    }
}
 Tai Le28 дек. 2016 г., 10:44
Ваш способ хорошо работает с одной строкой, но с несколькими строками (isWrapped = true) вы должны сначала вычислить строки текста, а затем обновитьyDiff = (height-lines*fontSize)/2 - lines*fontSize/10
 ios_user24 окт. 2018 г., 17:09
отлично! отлично сработано

но у меня сейчас тот же вопрос, и я решил проблему с последующим расследованием.

Выравнивание по вертикали зависит от текста, который вы хотите нарисовать, и шрифта, который вы используете, поэтому нет единого решения сделать его вертикальным для всех случаев.

Но мы все еще можем рассчитать вертикальную среднюю точку для разных случаев.

По словам AppleОб обработке текста в iOSнам нужно знать, как рисуется текст.

Например, я пытаюсь сделать вертикальное выравнивание для строк будних дней: Sun, Mon, Tue, ....

В этом случае высота текста зависит отВысота кепкии нетспуск для этих персонажей. Поэтому, если нам нужно выровнять этот текст по центру, мы можем рассчитать смещение символа верхней части заглавной буквы, например, Положение вершины символа "S".

Согласно рисунку ниже:

Верхний пробел для заглавной буквы "S" будет

font.ascender - font.capHeight

И нижний пробел для заглавной буквы "S" будет

font.descender + font.leading

Поэтому нам нужно немного сдвинуть "S" с вершины:

y = (font.ascender - font.capHeight + font.descender + font.leading + font.capHeight) / 2

Это равно:

y = (font.ascender + font.descender + font.leading) / 2

Затем я могу сделать текст вертикально выровненным по середине.

Заключение:

Если в вашем тексте нет символов, превышающих базовую линию, например, "p", "j", "g", и нет символа над верхней частью высоты кепки, например «Е». Вы можете использовать формулу выше, чтобы выровнять текст по вертикали.

y = (font.ascender + font.descender + font.leading) / 2

Если ваш текст включает символ ниже базовой линии, например, «p», «j» и ни один символ не превышает высоту верхнего уровня, например, «Е». Тогда вертикальная формула будет:

y = (font.ascender + font.descender) / 2

Если текст включает, не включает символ, нарисованный ниже базовой линии, например, «j», «p» и включает в себя символ, нарисованный над линией высоты колпачка, например, «Е». Тогда у будет:

y = (font.descender + font.leading) / 2

Если в вашем тексте встречаются все символы, то y равно:

y = font.leading / 2
 alpine16 мая 2017 г., 06:00
что значитy

этот ответ @iamkothed, Различия:

расчет высоты текста основан наNSString.size(with: Attributes), Я не знаю, если это улучшение по сравнению с(height-fontSize)/2 - fontSize/10, но мне нравится думать, что это так. Хотя, по моему опыту,NSString.size(with: Attributes) не всегда возвращает наиболее подходящий размер.добавленнойinvertedYAxis свойство. Это было полезно для моих целей экспорта этогоCATextLayer использование подклассаAVVideoCompositionCoreAnimationTool, AVFoundation работает по «нормальной» оси Y, и поэтому мне пришлось добавить это свойство.Работает только сNSString, Вы можете использовать Swift'sString класс, потому что он автоматически приводит кNSString.

ИгнорируетCATextLayer.fontSize собственность и полностью полагается наCATextLayer.font свойство, которое ДОЛЖНО бытьUIFont экземпляр.

class VerticallyCenteredTextLayer: CATextLayer {
    var invertedYAxis: Bool = true

    override func draw(in ctx: CGContext) {
        guard let text = string as? NSString, let font = self.font as? UIFont else {
            super.draw(in: ctx)
            return
        }

        let attributes = [NSAttributedString.Key.font: font]
        let textSize = text.size(withAttributes: attributes)
        var yDiff = (bounds.height - textSize.height) / 2
        if !invertedYAxis {
            yDiff = -yDiff
        }
        ctx.saveGState()
        ctx.translateBy(x: 0.0, y: yDiff)
        super.draw(in: ctx)
        ctx.restoreGState()
    }
}

где CATextLayer поместит базовую линию вашего текста. Как только вы это узнаете, сместите систему координат в слое, то есть отрегулируйте bounds.origin.y на разницу между тем, где обычно находится базовая линия, и тем, где вы хотите ее видеть, учитывая метрики шрифта.

CATextLayer немного чёрный ящик, и найти базовую линию будет немного сложно - см. Мойответ здесь для iOS - Я понятия не имею, что такое поведение на Mac.

но вы можете сделать то же самое, используя текстовые метрики:

http://developer.apple.com/library/ios/#documentation/UIKit/Reference/NSString_UIKit_Additions/Reference/Reference.html

... например, найдите размер текста, а затем используйте эту информацию, чтобы разместить его там, где вы хотите, в родительском слое. Надеюсь это поможет.

 t0rst20 окт. 2012 г., 12:10
Хорошее начало, за исключением того, что метрики, представленные добавлением строк UIKit, в большинстве случаев не точны для текста вCATextLayer на iOS - смотритеэтот ответ
 Mike26 нояб. 2011 г., 04:51
sizeWithFont для NSString не дает правильных результатов при работе с CATextLayer. Это дает высоту, превышающую то, что отображает CATextLayer. Так что не беспокойтесь об использовании текста со слоями ...

опоздать на ответ, но вы можете рассчитать размер текста, а затем установить положение textLayer. Также вам нужно поставить textLayer textAligment mode в "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];

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()
}
}

Ваш ответ на вопрос