iPhone - How to draw text in the middle of a rect

Swift 5

static func draw(_ text: String, _ rect: CGRect, _ font: UIFont) {

    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = .center
    let attributes = [
        NSAttributedString.Key.paragraphStyle: paragraphStyle,
        NSAttributedString.Key.font: font,
        NSAttributedString.Key.foregroundColor: UIColor.red
    ]
    NSAttributedString(string: text, attributes: attributes).draw(in: rect.insetBy(dx: 0, dy: (rect.height - font.pointSize)/2))
}

If you want to draw multiple lines,

 func drawMutipleLine(text: String = "Good morning how \nare you ,  fine, thank\nyou good day. uck wood?", 
                    _ rect: CGRect, 
                      font: UIFont =  UIFont(name: "HelveticaNeue-Thin", size: 15)!) -> UIImage {

    let renderer = UIGraphicsImageRenderer(size: rect.size)
    let image = renderer.image { ctx in
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = .center
        let font = UIFont(name: "HelveticaNeue-Thin", size: 15)!
        let attributes = [NSAttributedString.Key.font:font, NSAttributedString.Key.paragraphStyle: paragraphStyle]
        let numLines = text.split(separator: "\n").count + 1
        NSAttributedString(string: text, attributes: attributes).draw(in: rect.insetBy(dx: 0, dy: (rect.height - font.pointSize * CGFloat(numLines))/2))
    }
    return image
}

Well, the font property pointSize corresponds directly to the height in pixels of a NSString drawn in that UIFont, so your formula would be something like this:

- (void) drawString: (NSString*) s 
           withFont: (UIFont*) font 
             inRect: (CGRect) contextRect {

    CGFloat fontHeight = font.pointSize;
    CGFloat yOffset = (contextRect.size.height - fontHeight) / 2.0;

    CGRect textRect = CGRectMake(0, yOffset, contextRect.size.width, fontHeight);

    [s drawInRect: textRect 
         withFont: font 
    lineBreakMode: UILineBreakModeClip 
        alignment: UITextAlignmentCenter];
}

UITextAlignmentCenter handles the horizontal centering, so we use the full width of the contextRect. The lineBreakMode can be whatever you like.


Here's an updated version for iOS7.0+.

I've also improved on the above answer by using the sizeWithAttributes: method which returns the bounds of the text enabling you to properly position the text before drawing it. This removes the need to hardcode any adjustments which will break if you use a different size font or if you use a different font.

- (void) drawString: (NSString*) s
           withFont: (UIFont*) font
             inRect: (CGRect) contextRect {

    /// Make a copy of the default paragraph style
    NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
    /// Set line break mode
    paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
    /// Set text alignment
    paragraphStyle.alignment = NSTextAlignmentCenter;

    NSDictionary *attributes = @{ NSFontAttributeName: font,
                                  NSForegroundColorAttributeName: [UIColor whiteColor],
                                  NSParagraphStyleAttributeName: paragraphStyle };

    CGSize size = [s sizeWithAttributes:attributes];

    CGRect textRect = CGRectMake(contextRect.origin.x + floorf((contextRect.size.width - size.width) / 2),
                                 contextRect.origin.y + floorf((contextRect.size.height - size.height) / 2),
                                 size.width,
                                 size.height);

    [s drawInRect:textRect withAttributes:attributes];
}

Tags:

Iphone