AutoLayout + RTL + UILabel text alignment
You want NSTextAlignmentNatural
. That infers the text alignment from the loaded application language (not from the script).
For iOS 9 and later (using Xcode 7), you can set this in the storyboard (choose the --- alignment option). If you need to target earlier releases, you'll need to create an outlet to the label and set the alignment in awakeFromNib
.
- (void)awakeFromNib {
[[self label] setTextAlignment:NSTextAlignmentNatural];
}
UILabel text alignment when English and Hebrew mixed as text?
Here is a sample you could be inspired with.
Note: I don't know how you create your all text, so I don't know how you'll know what's in English or what in Hebrew, but you'll get the idea.
NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithString:@"I bless You, God, for creating the fruit of the vine:\n בָּרוּךְ אַתָּה יְיָ אֱלֹהֵֽינוּ מֶֽלֶךְ הָעוֹלָם, בּוֹרֵא פְּרִי הַגָּֽפֶן."];
NSMutableParagraphStyle *englishParagraphStyle = [[NSMutableParagraphStyle alloc] init];
[englishParagraphStyle setAlignment:NSTextAlignmentLeft];
NSMutableParagraphStyle *hebrewParagraphStyle = [[NSMutableParagraphStyle alloc] init];
[hebrewParagraphStyle setAlignment:NSTextAlignmentRight];
NSRange englishRange = NSMakeRange(0, [@"I bless You, God, for creating the fruit of the vine:" length]);
NSRange hebrewRange = NSMakeRange([@"I bless You, God, for creating the fruit of the vine:" length],
[[attrStr string] length] - [@"I bless You, God, for creating the fruit of the vine:" length]);
[attrStr addAttribute:NSParagraphStyleAttributeName
value:englishParagraphStyle
range:englishRange];
[attrStr addAttribute:NSParagraphStyleAttributeName
value:hebrewParagraphStyle
range:hebrewRange];
[myLabel setAttributedText:attrStr];
You also may want to do this before setting it to your UILabel
:
[attrStr addAttribute:NSFontAttributeName
value:[UIFont whateverFontWithWhateverSize]
range:NSMakeRange(0, [attrStr length])];
How to set top-left alignment for UILabel for iOS application?
Rather than re-explaining, I will link to this rather extensive & highly rated question/answer:
Vertically align text to top within a UILabel
The short answer is no, Apple didn't make this easy, but it is possible by changing the frame size.
Multiline UILabel with right-to-left text and auto adjusted font size
Don't set a specific height because of that is not expanding to your amount of text.
Steps 1 - Set top, leading, trailing and height constraint and change height relation to Greater Than or Equal to
Step 2 - label.numberOfLines = 0
Step 3 - label.sizeToFit()
step 4 - label.lineBreakMode = .byTruncatingTail
UILabel + AutoLayout = error in baseline alignment
Ok, with the last example the problem is more clear.
The first thing you must know: the text inside an UILabel is, by default, vertically aligned at the center of the label.
AFAIK you can't change the vertical align to have the text aligned to the base line.
Now, look at the attached image.
In the first example, I leaved all the default values of your sample project.
You can see that the day label and the description label are perfectly aligned: Autolayout aligns the bounds of the two labels (that are simply views, with other private subviews inside).
But, the font size is different. For the day label is the default system size (17), for the description you specified 20.
Now, if the two labels are aligned, the text is vertically center in the label, and the font size is different, obviously the baseline of the two text won't be aligned.
In the second example, I used the same font size, and you can see that the alignment is correct.
So, the possible solutions are two:
- use the same font (with the same size) in all the labels
- if you want to use fonts of different kind / size, you must change the position / size of the labels to have the baseline correctly aligned
This last point can be done with some calculation, and you can find some example here: Link
EDIT
Ok, I post an example.
First thing: it seems that, at the link posted, there is an error. ascender + descender + 1
is equal to the lineHeight
, and not to the pointSize
. I asked the author to correct it.
So, you can subclass UILabel, override viewForBaselineLayout and do something similar.
You have to add a baselineView
instance variable and add it as a subview of the UILabel
, since AutoLayout want the view to align to be a subview of the label.
// please note: you may need some error checking
- (UIView *)viewForBaselineLayout
{
// create the view if not exists, start with rect zero
if (!self.baselineView)
{
self.baselineView = [[UIView alloc] initWithFrame:CGRectZero];
self.baselineView.backgroundColor = [UIColor clearColor];
[self addSubview:self.baselineView];
}
// this is the total height of the label
float viewHeight = self.bounds.size.height;
// calculate the space that is above the text
float spaceAboveText = (viewHeight - self.font.lineHeight) / 2;
// this is the height of the view we want to align to
float baselineViewHeight = spaceAboveText + self.font.ascender + 1;
// if you have 26.6545 (for example), the view takes 26.0 for the height. This is not good, so we have to round the number correctly (to the upper value if >.5 and to the lower if <.5)
int integerBaseline = (int)(baselineViewHeight + 0.5f);
// update the frame of the view
self.baselineView.frame = CGRectMake(0, 0, self.bounds.size.width, (float)integerBaseline);
return self.baselineView;
}
With this approach you have to take care of few things:
- the label must have a size at the time autolayout calls
viewForBaselineLayout
, and its height must not change after. So you have to fit the label to it's content size before the layout process takes place. - you have adjust your constraints according to the above advice (now you are fixing, for example, dayLabel with monthLabel, but you can't since dayLabel must "float" now).
I attach your project with some updates and colors for debug, only with dayLabel and descriptionLabel (I removed the others) and with updated contraints.
Wrong Layout Updated
UIButton title alignment not changing to right direction in RTL
Use right alignment from storyboard as
or from programmatically as
buttonShowOnMap.contentHorizontalAlignment = .left//For left alignment
buttonShowOnMap.contentHorizontalAlignment = .right//For right alignment
How to change the text alignment throughout the app at once?
You can use UIAppearance
to set properties of ui elements throughout your entire app. This will work for all classes that adopt the UIAppearance
protocol (UILabel
, UIButton
, etc).
For eaxmple, the following code will change the text alignment of all labels in your app:
[[UILabel appearance] setTextAlignment:NSTextAlignmentRight];
IIRC, UINavigationBar
does not support UIAppearance
, meaning that you'll need to use a custom label for the title.
Related Topics
Module Compiled with Swift 4.0 Cannot Be Imported in Swift 4.0.1
Dealing with iPad Mini Screen Size
What Does Error "Thread 1:Exc_Bad_Instruction (Code=Exc_I386_Invop, Subcode=0X0)" Mean
How to Change My iOS Applications' Entitlements
Uialertview/Uialertcontroller iOS 7 and iOS 8 Compatibility
How to Embed Youtube Video on iOS and Play It Directly on Uiwebview Without Full Screen
Core Data: Do Child Contexts Ever Get Permanent Objectids for Newly Inserted Objects
How to Load an Uiimage into a Swiftui Image Asynchronously
Get Utc Time and Local Time from Nsdate Object
Control Cursor Position in Uitextfield
Example for Login Screen Modally Based on Storyboard
How to Read Data Structure from .Plist File into Nsarray
Posting JSON Data Using Afnetworking 2.0
iPhone In-App Purchase Store Kit Error -1003 "Cannot Connect to Itunes Store"
Why Maskstobounds = Yes Prevents Calayer Shadow