NSMutableParagraphStyle and NSAttributedString fail to wordrap - ios

I am attempting to have a multiline NSAttributedString, with a line spacing of 1.25.
NSMutableParagraphStyle *bodyFormat = [[NSMutableParagraphStyle alloc] init];
bodyFormat.alignment = NSTextAlignmentLeft;
//[bodyFormat setLineSpacing:5];
[bodyFormat setLineBreakMode:NSLineBreakByWordWrapping];
//[bodyFormat setMaximumLineHeight:5];
[bodyFormat setLineHeightMultiple:1.25];
NSMutableAttributedString *desc = [[NSMutableAttributedString alloc] initWithString:#"So why to use Lorem Ipsum and why placeholder text is necessary? Naturally, page designs that are made for text documents must contain some text rather than placeholder dots or something else. Howevr, should they contain a proper English words and sentenses almost every reader will deliberately try to interpret it eventually missing the design itself"];
[desc addAttribute:NSParagraphStyleAttributeName value:bodyFormat range:NSMakeRange(0, desc.length)];
UILabel *description = [[UILabel alloc] initWithFrame:CGRectMake(0,
20,
300,
1000)];
description.lineBreakMode = NSLineBreakByWordWrapping;
[description setAttributedText:desc];
[self.view addSubview:description];
This manages to produce a single line, and the linebreak is not effective.
What am I doing wrong?

[bodyFormat setLineSpacing:5];
breaks this behavior.
Also setting
description.numberOfLines = 0;
helps... (description is the UILabel)

Related

UITextView text give small gap between each word in middle of text

Team,
I have UITextView added content of text, with font family avinar roma, I noticed there is small gap in between each word which was not consistent. How to avoid the small gap in textview text for each word.
descriptionTextView = [[UITextView alloc] initWithFrame:CGRectMake(20, titlelabel.frame.origin.y + titlelabel.frame.size.height + 5, view.frame.size.width - 40, view.frame.size.height - 150)];
descriptionTextView.backgroundColor = [UIColor clearColor];
descriptionTextView.textColor = MH_PANTONE_444;
descriptionTextView.textAlignment = NSTextAlignmentCenter;
descriptionTextView.font = [UIFont fontWithName:MH_FONT_AVENIRROMAN size:MH_SCREEN_HEIGHT/48];
descriptionTextView.text = [descriptionArray objectAtIndex:index];
descriptionTextView.editable = NO;
descriptionTextView.scrollEnabled = NO;
descriptionTextView.selectable = YES;
descriptionTextView.dataDetectorTypes = UIDataDetectorTypeAll;
Please have image attached above
University Medical Center, is not same gap with remaining text.
Setting the hyphenationFactor should fix your problem. But you have to use NSAttributedString instead of plain text:
UIFont *font = [UIFont fontWithName: MH_FONT_AVENIRROMAN size: MH_SCREEN_HEIGHT/48];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.hyphenationFactor = 1.0;
NSDictionary *attributes = #{ NSFontAttributeName:font,
NSForegroundColorAttributeName: MH_PANTONE_444;
NSParagraphStyleAttributeName: paragraphStyle };
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString: [descriptionArray objectAtIndex:index]
attributes: attributes];
descriptionTextView.attributedText = attributedText;
https://developer.apple.com/reference/uikit/nsmutableparagraphstyle/1535553-hyphenationfactor
You may have to adjust the hyphenationFactor until you get the result you want. (0.0-1.0)
I solved the same issue by setting the leftView property of the UITextField to be an empty view with the size of the padding as desired:
UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 20)];
textView.leftView = paddingView;
textView.leftViewMode = UITextFieldViewModeAlways;
I had also face an issue of text alignment with custom fonts in iOS application, and that was with vertical alignment. I guess this is because of the custom font you are using in your application. But luckily there is a solution.
Every font file have some configurations about display the letter. One of the property is minLeftSideBearing for left spacing and minRightSideBearing for right spacing. I guess by changing them you can solve this spacing issue.
Follow the following link to check how to change this properties.
http://www.andyyardley.com/2012/04/24/custom-ios-fonts-and-how-to-fix-the-vertical-position-problem/
And as mention in above blog you need to install font tool. That you can download from following link.
https://developer.apple.com/download/more/?=font
Hope this might help you.
Thanks, Jay.

Text Kit not word-wrapping like Core Text with similar settings in UITextView

Using an exclusion path with a UITextView is not properly wrapping the words for the first and last line in the example shown (lower example). It does render properly using word-wrap with CoreText (top example image).
Here is the code for the UITextView (both use the same size bezier path, and both use the same font and paragraph settings)
NSString *testText = #"Text Kit exclusion paths ..."; //text truncated for brevity
UIBezierPath *viewPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 280, 280)];
UIBezierPath *shapePath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 265, 265)];
viewPath.usesEvenOddFillRule = true;
shapePath.usesEvenOddFillRule = true;
[shapePath appendPath:viewPath];
NSMutableAttributedString *title = [[NSMutableAttributedString alloc]initWithString:testText];
UIFont *font = [UIFont fontWithName:#"BradleyHandITCTT-Bold" size:14];
[title addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, title.length)];
//add color
[title addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0, title.length)];
//add alignment
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setAlignment:NSTextAlignmentCenter];
[paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
[title addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, title.length)];
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0.0, 370.0, 280, 280)];
textView.textContainerInset = UIEdgeInsetsMake(0,0,0,0);
textView.textContainer.exclusionPaths = #[shapePath];
[textView.textContainer setLineBreakMode:NSLineBreakByWordWrapping];
textView.contentInset = UIEdgeInsetsMake(0,0,0,0);
textView.attributedText = title;
textView.backgroundColor = [UIColor clearColor];
It is worth noting that the Text Kit is respecting the word wrapping rules except for the first and (possibly last) line where the text does not actually fit. I need this to work with a UITextView because text entry is required, or I would be done with my Core Text example. Swift answers are acceptable as well as obj-c.
How can I make UIKIt behave as it does with Core Text, or in other words properly word wrap all of the words in the example path provided?

UILabel with multiple chained NSAttributedString, with line limit, show the tail truncation with NSBackgroundColorAttributeName of unseen text

The dots are added automatically by the UILabel, cause of line limitation, but they get the background color of hidden truncated text:
So I have UILabel with line limit of 10 and line break mode of TruncatingTail.
I also have 2 types of attributed strings that build this UILabel content.
NSForegroundColorAttributeName, NSFontAttributeName
NSBackgroundColorAttributeName, NSForegroundColorAttributeName, NSFontAttributeName
Any idea why the UILabel is adding background color to the dots? There is text in line 12 (which is truncated) that have that background...
=Here Given Code Try it..
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:#"test"];
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
style.lineBreakMode = NSLineBreakByTruncatingTail;
[text addAttribute:NSParagraphStyleAttributeName
value:style
range:NSMakeRange(0, text.length)];
label.attributedText = text;
It looks like your NSAttributedString styling is picking up on an instance of "Windsor" that is past the truncation point.
You could find where the truncation occurs, and then only apply the text attribute to the range of the string up to the truncation point.
See this SO answer to calculate this range.
NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init];
paragraph.lineBreakMode = mylabel.lineBreakMode;
NSDictionary *attributes = #{NSFontAttributeName : mylabel.font,
NSParagraphStyleAttributeName : paragraph};
CGSize constrainedSize = CGSizeMake(mylabel.bounds.size.width, NSIntegerMax);
CGRect rect = [mylabel.text boundingRectWithSize:constrainedSize
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:attributes context:nil];
if (rect.size.height > mylabel.bounds.size.height) {
NSLog(#"TOO MUCH");
}

Only first NSParagraphStyle applied in NSAttributedString

Goal is to have a single NSAttributedString with a larger line height between paragraphs than within a paragraph, a fairly simple and common use case it seems to me. Here's my code:
NSMutableParagraphStyle *firstParagraphStyle = [[NSMutableParagraphStyle alloc] init];
firstParagraphStyle.lineHeightMultiple = 3.0;
NSMutableParagraphStyle *secondParagraphStyle = [[NSMutableParagraphStyle alloc] init];
secondParagraphStyle.lineHeightMultiple = 1.0;
NSAttributedString *title = [[NSAttributedString alloc] initWithString:#"Title"
attributes:#{NSParagraphStyleAttributeName: firstParagraphStyle}];
NSAttributedString *bodyTop = [[NSAttributedString alloc] initWithString:#"\u2029Body 1"
attributes:#{NSParagraphStyleAttributeName: secondParagraphStyle}];
NSAttributedString *bodyBottom = [[NSAttributedString alloc] initWithString:#"\u2029Body 2 line 1\u2028Body 2 line 2"
attributes:#{NSParagraphStyleAttributeName: secondParagraphStyle}];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init];
[attributedString appendAttributedString:title];
[attributedString appendAttributedString:bodyTop];
[attributedString appendAttributedString:bodyBottom];
All four lines end up with the same line spacing of 3.0. In fact, when I remove the attributes dictionary entirely and simply do:
NSAttributedString *title = [[NSAttributedString alloc] initWithString:#"Title"];
NSAttributedString *bodyTop = [[NSAttributedString alloc] initWithString:#"\u2029Body 1"];
NSAttributedString *bodyBottom = [[NSAttributedString alloc] initWithString:#"\u2029Body 2 line 1\u2028Body 2 line 2"];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init];
[attributedString appendAttributedString:title];
[attributedString appendAttributedString:bodyTop];
[attributedString appendAttributedString:bodyBottom];
[attributedString addAttribute:NSParagraphStyleAttributeName
value:firstParagraphStyle
range:NSMakeRange(0, 1)];
[attributedString addAttribute:NSParagraphStyleAttributeName
value:secondParagraphStyle
range:NSMakeRange(1, attributedString.length - 1)];
it still renders all three paragraphs using line height multiple of 3.0. It seems that whatever the first paragraph style I apply to the string is, that's the one that applies to all subsequent lines and paragraphs!
Why doesn't using the special paragraph separator character \u2029 as Apple suggests here allow for more than one paragraph style within a single NSAttributedString? I'd prefer not to break into multiple UILabels.
Thanks in advance to anyone with deep Core Text knowledge on this subject.
Ended up getting this working. Turns out when I set alignment on the subsequent UILabel to .textAlignment = NSTextAlignmentCenter that messed up the paragraph style for the entire attributedText.
So the lesson is: If you're using multiple paragraph styles, don't set any corresponding properties on the UILabel or your behavior will be clobbered by the first paragraph style the label sees, even when the properties aren't related (e.g. line height and text alignment).

Chinese characters interline spacing in UITextView

I have translated an app into Simplified Chinese.
The app is using a UITextView and the contents of it is Simplified Chinese text.
I have noticed that (sometimes not always) the interline spacing is wrong, the lines are practically touching each other :
I am setting the contents of the UITextview via an attributed string that I create based on a required pointsize like this:
-(NSMutableAttributedString*) textWithPointSize:(CGFloat)pointSize
{
UIFont * myFontDescr = [UIFont systemFontOfSize:pointSize];
NSMutableAttributedString * description = [[NSMutableAttributedString alloc] initWithString:self.exercise.descr attributes:#{NSFontAttributeName:myFontDescr}];
UIFont * myFontTips = [UIFont italicSystemFontOfSize:pointSize];
NSMutableAttributedString * tips = [[NSMutableAttributedString alloc] initWithString:self.exercise.tips attributes:#{NSFontAttributeName:myFontTips}];
NSMutableAttributedString * text = [[NSMutableAttributedString alloc] initWithAttributedString:description];
[text appendAttributedString:[[NSAttributedString alloc] initWithString:#"\n\n"]];
[text appendAttributedString:tips];
return text;
}
I am using the systemFontOfSize: function, I guess this should handle Chinese characters correctly? Any ideas why this could be happening?
I did not find out why but I implemented a work around by explicitly setting the interline spacing (only when language is Chinese) like this:
//for chinese language we have detected a problem with the interline spacing
//it does happen randomly, and so to workaround this we set the linespacing explicitly
if ( [NSLocalizedString(#"__CurrentLanguage",#"zh-Hans") isEqualToString:#"zh-Hans"] ) {
//make paragraph styl with interline spacing
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineSpacing = 0.25 * pointSize;
//font for description
UIFont * myFontDescr = [UIFont systemFontOfSize:pointSize];
NSMutableAttributedString * description = [[NSMutableAttributedString alloc] initWithString:self.exercise.descr attributes:#{NSFontAttributeName:myFontDescr, NSParagraphStyleAttributeName:paragraphStyle}];
//font for tips
UIFont * myFontTips = [UIFont italicSystemFontOfSize:pointSize];
NSMutableAttributedString * tips = [[NSMutableAttributedString alloc] initWithString:self.exercise.tips attributes:#{NSFontAttributeName:myFontTips,NSParagraphStyleAttributeName:paragraphStyle}];
//add description then...
NSMutableAttributedString * text = [[NSMutableAttributedString alloc] initWithAttributedString:description];
//concat the tips (with 2x newline in between)
[text appendAttributedString:[[NSAttributedString alloc] initWithString:#"\n\n"]];
[text appendAttributedString:tips];
//return value
return text;
}
//its not chinese, so do "normal" stuff

Resources