How to draw vertical text in UILabel
Asked Answered
C

7

28

I'm currently working on drawing vertical Chinese text in a label. Here's what I am trying to achieve, albeit with Chinese Characters:

Express

I've been planning to draw each character, rotate each character 90 degrees to the left, then rotating the entire label via affine transformations to get the final result. However, it feels awfully complicated. Is there an easier way to draw the text without complicated CoreGraphics magic that I'm missing?

Calypso answered 9/3, 2012 at 3:50 Comment(1)
what you are doing is fine. Its not complicatedKyl
W
37

Well, You can do like below:

labelObject.numberOfLines = 0;
labelObject.lineBreakMode = NSLineBreakByCharWrapping;

and setFrame with -- height:100, width:20 It will work fine..

Wheatley answered 9/3, 2012 at 4:17 Comment(2)
Clunky, but I did it this way in the end.Calypso
Since iOS 6.0 UILineBreakModeCharacterWrap is deprecated. Use NSLineBreakByCharWrapping instead.Conscionable
I
22

It works

UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 30, 100)];
lbl.transform = CGAffineTransformMakeRotation((M_PI)/2);
Irresolvable answered 9/3, 2012 at 8:33 Comment(1)
+1, while this doesn't exactly answer OP's question (this will also rotate characters, while he clearly wanted column-styled text) it's a very useful answer for others who, like me, actually wanted a rotated textPurdah
R
12

Tried the method offered by Simha.IC but it didn't work well for me. Some characters are thinner than others and get placed two on a line. E.g.

W
ai
ti
n
g

The solution for me was to create a method that transforms the string itself into a multiline text by adding \n after each character. Here's the method:

- (NSString *)transformStringToVertical:(NSString *)originalString
{
    NSMutableString *mutableString = [NSMutableString stringWithString:originalString];
    NSRange stringRange = [mutableString rangeOfString:mutableString];

    for (int i = 1; i < stringRange.length*2 - 2; i+=2)
    {
        [mutableString insertString:@"\n" atIndex:i];
    }

    return mutableString;
}

Then you just setup the label like this:

label.text = [self transformStringToVertical:myString];
CGRect labelFrame = label.frame;
labelFrame.size.width  = label.font.pointSize;
labelFrame.size.height = label.font.lineHeight * myString.length;
label.frame = labelFrame;

Enjoy!

Reichel answered 26/9, 2014 at 9:1 Comment(1)
I used this method but in Swift 3.0 with: var newString:String = "" for i in 0 ..< originalString.characters.count{ newString += "\(originalString[originalString.index(originalString.startIndex, offsetBy: i)])\n" }Rearward
T
8

If you would like to rotate the whole label (including characters), you can do so as follows:

  1. First add the QuartzCore library to your project.
  2. Create a label:

    UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 300.0, 30.0)];
    [label setText:@"Label Text"];
    
  3. Rotate the label:

    [label setTransform:CGAffineTransformMakeRotation(-M_PI / 2)];
    

Depending on how you'd like to position the label you may need to set the anchor point. This sets the point around which a rotation occurs. Eg:

    [label.layer setAnchorPoint:CGPointMake(0.0, 1.0)];
Torrential answered 20/7, 2012 at 10:37 Comment(1)
All answers work but this is best one. I made (-m_pi/4) and it looks cool. ThanksFuzzy
D
6

This is another way to draw vertical text, by subclassing UILabel. But it is some kind different of what the question want.

Objective-C

@implementation MyVerticalLabel

// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGAffineTransform transform = CGAffineTransformMakeRotation(-M_PI_2);
    CGContextConcatCTM(context, transform);
    CGContextTranslateCTM(context, -rect.size.height, 0);

    CGRect newRect = CGRectApplyAffineTransform(rect, transform);
    newRect.origin = CGPointZero;

    NSMutableParagraphStyle *textStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
    textStyle.lineBreakMode = self.lineBreakMode;
    textStyle.alignment = self.textAlignment;

    NSDictionary *attributeDict =
    @{
      NSFontAttributeName : self.font,
      NSForegroundColorAttributeName : self.textColor,
      NSParagraphStyleAttributeName : textStyle,
      };
    [self.text drawInRect:newRect withAttributes:attributeDict];
}
@end

A sample image is following:

A sample image

Swift

It can put on the storyboard, and watch the result directly. Like the image, it's frame will contain the vertical text. And text attributes, like textAlignment, font, work well too.

A vertical text example

@IBDesignable
class MyVerticalLabel: UILabel {

    override func drawRect(rect: CGRect) {
        guard let text = self.text else {
            return
        }

        // Drawing code
        let context = UIGraphicsGetCurrentContext()

        let transform = CGAffineTransformMakeRotation( CGFloat(-M_PI_2))
        CGContextConcatCTM(context, transform)
        CGContextTranslateCTM(context, -rect.size.height, 0)

        var newRect = CGRectApplyAffineTransform(rect, transform)
        newRect.origin = CGPointZero

        let textStyle = NSMutableParagraphStyle.defaultParagraphStyle().mutableCopy() as! NSMutableParagraphStyle
        textStyle.lineBreakMode = self.lineBreakMode
        textStyle.alignment = self.textAlignment

        let attributeDict: [String:AnyObject] = [
            NSFontAttributeName: self.font,
            NSForegroundColorAttributeName: self.textColor,
            NSParagraphStyleAttributeName: textStyle,
        ]

        let nsStr = text as NSString
        nsStr.drawInRect(newRect, withAttributes: attributeDict)
    }

}

Swift 4

override func draw(_ rect: CGRect) {
    guard let text = self.text else {
        return
    }

    // Drawing code
    if let context = UIGraphicsGetCurrentContext() {
        let transform = CGAffineTransform( rotationAngle: CGFloat(-Double.pi/2))
        context.concatenate(transform)
        context.translateBy(x: -rect.size.height, y: 0)
        var newRect = rect.applying(transform)
        newRect.origin = CGPoint.zero

        let textStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
        textStyle.lineBreakMode = self.lineBreakMode
        textStyle.alignment = self.textAlignment

        let attributeDict: [NSAttributedStringKey: AnyObject] = [NSAttributedStringKey.font: self.font, NSAttributedStringKey.foregroundColor: self.textColor, NSAttributedStringKey.paragraphStyle: textStyle]

        let nsStr = text as NSString
        nsStr.draw(in: newRect, withAttributes: attributeDict)
    }
}
Decalcomania answered 2/11, 2015 at 8:15 Comment(0)
R
1

Swift 5

More easy way with CGAffineTransform

import UIKit
class ViewController: UIViewController {

@IBOutlet weak var verticalText: UILabel

    override func viewDidLoad() {

        verticalText.transform = CGAffineTransform(rotationAngle:CGFloat.pi/2)
    }
}
Rhombohedral answered 10/4, 2021 at 8:27 Comment(1)
But then the letters are sidewaysMicropaleontology
A
0
import UIKit

class VerticalLabel : UILabel {
    
    private var _text : String? = nil
    
    override var text : String? {
        get {
            return _text
        }
        set {
            self.numberOfLines = 0
            self.textAlignment = .center
            self.lineBreakMode = .byWordWrapping
            _text = newValue
            if let t = _text {
                var s = ""
                for c in t {
                    s += "\(c)\n"
                }
                super.text = s
            }
        }
    }
    
}
Alcina answered 17/11, 2020 at 14:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.