If you came to this question based on the title but are not interested in Mongolian, you might be looking for this Q&A instead:
I've been learning Swift in order to develop iOS apps for traditional Mongolian. The problem is that traditional Mongolian is written vertically from top to bottom and from left to right. My question is how do I display text vertically and still have line wrapping work?
If you stay with me for a minute, I'll try to explain the problem more clearly. Below is an image of the kind of text view I would like to achieve. In case the foreign script throws you off, I have included English text that follows the same pattern. In fact, if the app has any English text to display, this is how it should look.
For a simple one-line UILabel, a 90 degree clockwise rotation would work. However, for a multi-line UITextView I need to deal with line wrapping. If I just do a plain 90 degree rotation, the first thing written will end up being on the last line.
So far I have made a plan that I think can overcome this problem:
That should take care of the text wrap.
I can do the mirrored font. However, I don't know how to do the Swift coding for the rotation and mirroring of the UITextView. I've found the following links that seem to give hints to parts of the solution, but they are all in Objective C and not in Swift.
There are traditional Mongolian apps in the app store (like this and this) but I haven't found anyone yet who is sharing their source code, so I don't know what they are doing behind the scenes to display the text. I plan to make my code open source so that it is not so hard for others in the future to develop apps for the several million people who read traditional Mongolian. Any assistance you can give to this endeavor would be much appreciated, not just by me but also by the Mongolian people. Even if you don't know yourself, upvoting this question to make it more visible would help.
@sangonz's answer is still a great answer, but I temporarily unmarked it as the accepted answer because I just couldn't get everything to work. Specifically:
Up to this point I have been using the original method I proposed above, but what I really want is to get something like what @sangonz proposed working.
I am also now considering alternate methods like
UITextView
Swift5 UILabel Extension. Use this code in that case. Show activity on this post. Change the text property to attributed and select the text and right click to get the font property. Click on the strikethrough.
A view that displays one or more lines of informational text.
Edit: This is how I finally did it.
Here's a very basic implementation in my GitHub: Vertical-Text-iOS.
Nothing fancy, but it works. Finally I had to mix TextKit and image processing. Take a look at the code. It involves:
NSTextContainer
to get the right text dimensions.UIView
to render the text applying affine transformations to each line and rendering using NSLayoutManager
to keep all TextKit features.The proper way to keep all native text benefits (e.g. highlighting, selection...) is to use standard TextKit APIs. The method you are proposing would break all that or would possibly result in strange behaviour.
However, looks like TextKit in iOS does not support vertical orientation out-of-the-box yet, but it is prepared for that. As a side note, in OS X it is somewhat supported and you could call textView.setLayoutOrientation(.Vertical)
, but it still has some limitations.
The
NSTextLayoutOrientationProvider
protocol defines an interface providing the default orientation for text laid out in a conforming object, in absence of an explicitNSVerticalGlyphFormAttributeName
attribute. The only UIKit class that implements this interface isNSTextContainer
, whose default implementation returnsNSTextLayoutOrientationHorizontal
. AnNSTextContainer
subclass that handles vertical text could set this property toNSTextLayoutOrientationVertical
to support the custom layout orientation logic.
Source: UIKit > NSTextLayoutOrientationProvider
Protocol Reference for iOS
In conclusion, you should start subclassing NSTextContainer
, and you will have to deal with NSLayoutManager
and NSTextContainer
a lot.
If, on the other hand you decide to follow your custom text rendering I suggest the following approach.
CGImage
as a result.UIImage
and setting the correct UIImageOrientation
value.UIScrollView
that only allows horizontal scrolling.Beware this method renders the whole text, so don't use it for very long texts. If you need to do that, you will need to consider a tiling approach. Watch WWDC 2013 > 217 - Exploring Scroll Views on iOS 7.
Good luck!
Update: (image from github project)
If you're going to rotate the text I would suggest using a right-to-left layout so that you can skip the mirroring step (and just rotate the other way).
You should be able to just set the label/textview's transform
property:
view.transform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(CGFloat(-M_PI_2)), view.bounds.width, view.bounds.height)
You need to translate after you rotate because the view rotates around its origin (in the upper left).
The good news is that gestures and taps are transformed at the same time the pixels are, so controls continue to work the way you expect them to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With