vertically align text in a CATextLayer?

后端 未结 15 1331
时光说笑
时光说笑 2020-12-10 10:41

I am working on a CATextLayer that I want to use in both Mac and iOS. Can I control the vertical alignment of the text within the layer?

In this particular case, I

相关标签:
15条回答
  • 2020-12-10 11:25

    So there is no "direct" way of doing this but you can accomplish the same thing by using text metrics:

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

    ... for example, find the size of the text then use that information to place it where you want in the parent layer. Hope this helps.

    0 讨论(0)
  • 2020-12-10 11:26

    I'd like to propose a solution that takes multiline wrapping inside the available box into account:

    final class CACenteredTextLayer: CATextLayer {
        override func draw(in ctx: CGContext) {
            guard let attributedString = string as? NSAttributedString else { return }
    
            let height = self.bounds.size.height
            let boundingRect: CGRect = attributedString.boundingRect(
                with: CGSize(width: bounds.width,
                             height: CGFloat.greatestFiniteMagnitude),
                options: NSString.DrawingOptions.usesLineFragmentOrigin,
                context: nil)
            let yDiff: CGFloat = (height - boundingRect.size.height) / 2
    
            ctx.saveGState()
            ctx.translateBy(x: 0.0, y: yDiff)
            super.draw(in: ctx)
            ctx.restoreGState()
        }
    }
    
    0 讨论(0)
  • 2020-12-10 11:26

    Swift 5.3 for macOS

    class VerticallyAlignedTextLayer : CATextLayer {
        /* Credit - purebreadd - 6/24/2020
            https://stackoverflow.com/questions/4765461/vertically-align-text-in-a-catextlayer
         */
    
        func calculateMaxLines() -> Int {
            let maxSize = CGSize(width: frame.size.width, height: frame.size.width)
            let font = NSFont(descriptor: self.font!.fontDescriptor, size: self.fontSize)
            let charSize = floor(font!.capHeight)
            let text = (self.string ?? "") as! NSString
            let textSize = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font!], context: nil)
            let linesRoundedUp = Int(floor(textSize.height/charSize))
            return linesRoundedUp
        }
            
        override func draw(in context: CGContext) {
            let height = self.bounds.size.height
            let fontSize = self.fontSize
            let lines = CGFloat(calculateMaxLines())
            let yDiff = -(height - lines * fontSize) / 2 - lines * fontSize / 6.5 // Use -(height  - lines * fontSize) / 2 - lines * fontSize / 6.5 when in non-flipped coordinates (like macOS's default)
    
            context.saveGState()
            context.translateBy(x: 0, y: yDiff)
            super.draw(in: context)
            context.restoreGState()
        }
    }
    
    

    Notice I am dividing fontSize by 6.5, which seems to work better for my application of this solution. Thanks @purebreadd!

    0 讨论(0)
提交回复
热议问题