NSAttributedString end of first line indent - ios

I want to have the first line in an NSAttributedString for a UITextView indented from the right side on the first line.
So the firstLineHeadIndent in NSParagraphStyle will indent the first line from the left. I want to do the same thing but from the right in my UITextView.
Here's a screenshot of how I want the text to wrap.

The Setting Text Margins article from the Text System User Interface Layer Programming Guide has this figure:
As you can see, there's no built-in mechanism to have a first line tail indent.
However, NSTextContainer has a property exclusionPaths which represents parts of its rectangular area from which text should be excluded. So, you could add a path for the upper-right corner to prevent text from going there.
UIBezierPath* path = /* compute path for upper-right portion that you want to exclude */;
NSMutableArray* paths = [textView.textContainer.exclusionPaths mutableCopy];
[paths addObject:path];
textView.textContainer.exclusionPaths = paths;

I'd suggest to create 2 different NSParagraphStyle: one specific for the first line and the second one for the rest of the text.
//Creating first Line Paragraph Style
NSMutableParagraphStyle *firstLineStyle = [[NSMutableParagraphStyle alloc] init];
[firstLineStyle setFirstLineHeadIndent:10];
[firstLineStyle setTailIndent:200]; //Note that according to the doc, it's in point, and go from the origin text (left for most case) to the end, it's more a length that a "margin" (from right) that's why I put a "high value"
//Read there: https://developer.apple.com/library/ios/documentation/Cocoa/Reference/ApplicationKit/Classes/NSMutableParagraphStyle_Class/index.html#//apple_ref/occ/instp/NSMutableParagraphStyle/tailIndent
//Creating Rest of Text Paragraph Style
NSMutableParagraphStyle *restOfTextStyle = [[NSMutableParagraphStyle alloc] init];
[restOfTextStyle setAlignement:NSTextAlignmentJustified];
//Other settings if needed
//Creating the NSAttributedString
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:originalString];
[attributedString addAttribute:NSParagraphStyleAttributeName value:firstLineStyle range:rangeOfFirstLine];
[attributedString addAttribute:NSParagraphStyleAttributeName
value:restOfTextStyle
range:NSMakeRange(rangeOfFirstLine.location+rangeOfFirstLine.length,
[originalString length]-(rangeOfFirstLine.location+rangeOfFirstLine.length))];
//Setting the NSAttributedString to your UITextView
[yourTextView setAttributedText:attributedString];

Related

NSLineBreakByTruncatingTail on UITextView removing new line breaks

I have a UITextView with attributedText that has multiple new line breaks included in its attributed string.
NSMutableAttributedString *info = [[NSMutableAttributedString alloc] initWithString:#""];
NSAttributedString *title = [[NSAttributedString alloc] initWithString: [NSString stringWithFormat:#"%#\n", item.title] attributes:titleAttributes];
NSAttributedString *description = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:#"%#\n\n", description] attributes:descriptionAttributes]
[info appendAttributedString:bioItemTitle];
[info appendAttributedString:bioItemDescription];
textView.attributedText = info;
I've set the lineBreakMode of the textView's textContainer to NSLineBreakByTruncatingTail.
textView.textContainer.lineBreakMode = NSLineBreakByTruncatingTail;
The textView's textContainer also has a maximum number of lines.
textView.textContainer.maximumNumberOfLines = 8;
The problem arises when the 8th line of the textView is a new line, and not a line of characters. The textContainer truncates by removing the new line and replacing it with the next line of written characters.
How do I preserve the new line while still setting a lineBreakMode?
See screenshots
Try using UILabel instead of UITextView. It seems to play nicer in regard to truncating a new line.
Random things to try on the off chance you haven't already that aren't even solutions but maybe workarounds, and may not work anyway, but whatever:
Change the maximumNumberOfLines to 0 and rely on frames/autolayout to size the text view and its container, perhaps in combination with setting the text container's heightTracksTextView property to true
Insert horizontal whitespace or invisibles at the beginning of lines that otherwise only contain a newline #hacky

iOS : UILabel multiple lines - second line of label needs to start with 10 pixels

I am facing one issue that is - I have one label like "1. The Seibl is a software made by the some company and can be purchased at $500"
When it comes to iPhone 4s, the label is printing second line and second line is starting exactly under "1.". I would like to give space/margin/space so that label looks like numbering format.
Try this solution. It might helps you.
Use an NSAttributedString for your label, and set the headIndent of its paragraph style:
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
style.headIndent = 14;
NSDictionary *attributes = #{
NSParagraphStyleAttributeName: style
};
NSAttributedString *richText = [[NSAttributedString alloc] initWithString:#"So this UILabel walks into a bar…" attributes:attributes];
self.narrowLabel.attributedText = richText;
self.wideLabel.attributedText = richText;
Result:
Take a look at using a TextView instead, and modifying its textStorage property to define an exclusion area so that a new line is inset. Here's a link to the documentation.

Indent second line of UILabel

So I have a UILabel that may or may not go to a second line, depending if it is on iPhone or iPad. What I would like to accomplish is to have it indent on the second line to line up correctly, if needed.
On iPad it will almost never need the second line break, and depending on which iPhone it is running on, it may or may not. So, in essence, I need a way to dynamically indent the second line, only when there is a second line.
Use an NSAttributedString for your label, and set the headIndent of its paragraph style:
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
style.headIndent = 14;
NSDictionary *attributes = #{
NSParagraphStyleAttributeName: style
};
NSAttributedString *richText = [[NSAttributedString alloc] initWithString:#"So this UILabel walks into a bar…" attributes:attributes];
self.narrowLabel.attributedText = richText;
self.wideLabel.attributedText = richText;
Result:

How to wrap text around attachments using iOS7 Text Kit?

I am using the new Text Kit API to add attachments to some attributed text:
// create an attachment for each image
NSTextAttachment* ta = [NSTextAttachment new];
ta.image = [UIImage imageNamed:#"imageName"];
// add to the attributed text string
NSAttributedString* rep = [NSAttributedString attributedStringWithAttachment:ta];
[myAttributedTextString appendAttributedString:rep];
This works fine, I can see my image rendered in the output. However, I cannot find any way to specify the image alignment, or wrap text around the image.
Any ideas?
NOTE: Text attachments are different from exclusions paths - a text attachment is part of the 'model', i.e. it is part of the attributed text string that the layout manager performs text layout on. Whereas an exclusion path is part of the view.
NSTextAttachments are treated as a single character by NSAttributedString. So, in order to adjust their alignment you must do so as you would for text. It took me hours of fiddling with attachment.bounds (which I never could get to work properly) to finally figure this out. Here's an example of how to horizontally align an NSTextAttachment.
#def BETWEEN_SECTION_SPACING 10
// creates a text attachment with an image
NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
attachment.image = [UIImage imageNamed:#"sample_image.jpg"];
NSMutableAttributedString *imageAttrString = [[NSAttributedString attributedStringWithAttachment:attachment] mutableCopy];
// sets the paragraph styling of the text attachment
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init] ;
[paragraphStyle setAlignment:NSTextAlignmentCenter]; // centers image horizontally
[paragraphStyle setParagraphSpacing:BETWEEN_SECTION_SPACING]; // adds some padding between the image and the following section
[imageAttrString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [imageAttrString length])];
After this, you would append imageAttrString to an existing attributed string and perhaps append another after it. One quirk is that because the attachment is a character it is not treated as its own paragraph. In order for that to be the case you will need to surround it with \n (newline characters). Just append these to both sides of the attachment's attributed string.
Hope that helps, it took me ages to figure out.
Try setting the bounds property to the image size.
Defines the layout bounds of the receiver's graphical representation in the text coordinate system.
So it should be:
ta.bounds = (CGRect) { 0, 0, ta.image.size };
ta.bounds = (CGRect) { 0, yPadding, ta.image.size };
change yPadding you need.
It can be negative when image's height is large than line height.

UILabel attributedText with multiple line break modes

I have a requirement of showing a UILabel with text that has two different styles (different colours, parts of the text bolded). This is solved easily enough by using the attributedText-property.
My problem is that the text may or may not be longer than what I can fit in my label. When using plain text everything works the way I want it to. The text is word wrapped to fit the number of lines in the label and the tail is truncated if/when the text is longer than can be shown in the label.
When I switch to using attributedText I am only able to choose between tail truncation and word wrapping. If I want the tail truncated the label only renders a single line with the truncated tail (even though it could fit 10 lines). If I choose word wrapping then the tail is not truncated but the lines that cannot fit in the label are simply not shown.
My content string does not contain any line breaks, it is simply one long string.
I missed truncation when I set linespacing, but all I had to to was add linebreakmode to paragraphstyle
NSMutableParagraphStyle *paragrahStyle = [[NSMutableParagraphStyle alloc] init];
[paragrahStyle setLineSpacing:1.5];
[paragrahStyle setLineBreakMode:NSLineBreakByTruncatingTail];
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:#"Long string that truncates"];
[attributedText addAttribute:NSParagraphStyleAttributeName value:paragrahStyle range:NSMakeRange(0, [attributedText length])];
self.label.attributedText = attributedText;
They only way I've been able to get this to work is to not set a paragraph style.
try this:
[_text drawWithRect:_textRect
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine
attributes:attributes
context:nil];
You can set up an NSParagraphStyle with any lineBreakMode you please, and apply it to the string using NSParagraphStyleAttributeName. I don't know if all of the values of NSLineBreakMode are supported, but I have no reason to believe they aren't.

Resources