How to format a string for proper display in ios - ios

I have a FAQ section in my app, but I have to present it in a certain way using a non-editable UITextView. Just like below,
How can I cancel a recording?
A. You can cancel a recording while it is in progress by pressing the cancel (red ‘X’) button
in the center of the speaker on the recording screen. The audio recording
will not be saved.
But the problem is as you can see the has to be shown with some padding and the next line should start just below the answer line "not below the A". And there's a huge document of questions so I cannot format it manually. And it for both iPhone and iPad so I the UITextView width differs. Is there any solution to this kind of problem ?

I'd suggest to use NSAttributedString and the NSParagraphStyle combined with NSParagraphAttributeName.
Here is a example:
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:yourString];
int indent1 = 0;
int indent2 = 20;
int indent3 = 2*indent2;
NSMutableParagraphStyle *styleTitleByNumber = [[NSMutableParagraphStyle alloc] init];
[styleTitleByNumber setFirstLineHeadIndent:indent1];
[styleTitleByNumber setHeadIndent:indent1];
NSMutableParagraphStyle *styleTitleByLetter = [[NSMutableParagraphStyle alloc] init];
[styleTitleByLetter setFirstLineHeadIndent:indent2];
[styleTitleByLetter setHeadIndent:indent2];
NSMutableParagraphStyle *styleSimpleText = [[NSMutableParagraphStyle alloc] init];
[styleSimpleText setFirstLineHeadIndent:indent3];
[styleSimpleText setHeadIndent:indent3];
[attributedString addAttribute:NSParagraphStyleAttributeName
value:styleTitleByNumber
range:rangeOfTitleByNumber];
[attributedString addAttribute:NSParagraphStyleAttributeName
value:styleTitleByLetter
range:rangeOfTitleByLetter];
[attributedString addAttribute:NSParagraphStyleAttributeName
value:styleSimpleText
range:rangeOfSimpleText];
[yourTextView setAttributedText:attributedString];
Now, depending how is formatted your initial text, I leave you the way to know where to apply which style (for the NSRange parameter), or you can also, if the different parts are separated apply a direct effect on the NSAttributedString, and then combine them all.

Related

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:

NSAttributedString end of first line indent

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];

NSMutableAttributedString's attribute NSStrikethroughStyleAttributeName doesn't work correctly in iOS8

I have a mutable attributed string without NSStrikethroughStyleAttributeName attribute like this:
NSMutableAttributedString *str1 = [[NSMutableAttributedString alloc] initWithString:#"aaaa" attributes:#{NSStrikethroughStyleAttributeName:[NSNumber numberWithInteger:NSUnderlineStyleSingle]}];
and another mutable attributed string with NSStrikethroughStyleAttributeName attribute like this:
NSMutableAttributedString *str2 = [[NSMutableAttributedString alloc] initWithString:#"bbbb"];
and a whole string containing two strings above:
NSMutableAttributedString *labelString = [[NSMutableAttributedString alloc] init];
[labelString appendAttributedString:str1];
[labelString appendAttributedString:str2];
when I attach the whole string to a UILabel:
_label.attributedText = labelString;
It both display well in iOS7 and iOS8, like this:
aaaabbbb
But when I exchange their positions:
[labelString appendAttributedString:str2];
[labelString appendAttributedString:str1];
It display correctly in iOS7 but not correctly in iOS8
ios7: bbbbaaaa ios8: bbbbaaaa
It seems that in iOS8, UILabel doesn't render the strikethrough correctly if the first character in the attributed string is not strikethroughed.
I think this is a bug in iOS8, is there anyone who encounter the same problem with me?
NSMutableAttributedString *str2 = [[NSMutableAttributedString alloc] initWithString:#"bbbb" attributes:#{NSStrikethroughStyleAttributeName:[NSNumber numberWithInteger:NSUnderlineStyleNone]}];
it should help
On iOS8.1.1 we have more problems with setting NSMutableAttributedString, like with NSStrikethroughStyleAttributeName.
If your attributes are not changing try this and it will be.
I started reasoning by the UILabel that is spirit to chaneger attributes, so if we assume that the NSStrikethroughStyleAttributeName not initialized the label text so we will need the initialize it .
What I do is initializing mutableAttributedString by a none NSStrikethroughStyleAttributeName and change this attribute to highlight:
result is:
 
NSMutableAttributedString * string = [[NSMutableAttributedString alloc] initWithString: myString attributes: # {NSStrikethroughStyleAttributeName: # (NSUnderlineStyleNone)}];
             [string addAttributes: # {NSStrikethroughStyleAttributeName: # (NSUnderlineStyleSingle)} range: [myString rangeOfString: mySubString]];
[MyLabel setAttributedText: string];
effective result <= iOS8.1.1
Fix for the bug in iOS8: Strike Through first letter of the string with clear color and then Strike through the text in which ever range you want.
When you are not starting the index from 0, try this:
NSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc] initWithString:#"Hello"];
[attributedStr addAttributes:#{NSStrikethroughStyleAttributeName : #(NSUnderlineStyleSingle)} range:NSMakeRange(1, str.length)];
[attributedStr addAttributes:#{NSStrikethroughStyleAttributeName : #(NSUnderlineStyleNone)} range:NSMakeRange(0, 1)];
When you add NSStrikethroughStyleAttributeName, you should also add NSBaselineOffsetAttributeName, which is set to 0. And in swift, you should use the rawValue of NSUnderlineStyle.
I see the same issue and changing NSStrikethroughStyleAttributeName's value to NSUnderlineStyleNone doesn't fix it. Sure seems like iOS 8 bug.

Multiple paragraphSpacing in NSMutableParagraphStyle

In NSMutableParagraphStyle the paragraphSpacing Works perfectly fine.
but i am using bullet points also.
When user Press Return(Enter) then new Paragraph will come.
so when User type bullet points in Uitextview then in between two Points the paragaph spacing should be small and in rest of all the paragraph spacing is something high.
My code is...
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.minimumLineHeight = 0.f;
paragraphStyle.maximumLineHeight = 16.f;
paragraphStyle.firstLineHeadIndent = 16.0;
paragraphStyle.paragraphSpacing = 7.0;
paragraphStyle.lineSpacing = 5.0;
paragraphStyle.headIndent = 16.0;
paragraphStyle.lineBreakMode=NSLineBreakByWordWrapping;
paragraphStyle.tailIndent=305.0;
mutattstr1 = [[NSMutableAttributedString alloc] initWithAttributedString:txtViewOfNotes.attributedText];
[mutattstr1 addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, mutattstr1.length)];
[txtViewOfNotes setAttributedText:mutattstr1];
Like in this text view i need to give small space in between two bullet points line.
So, how to get multiple line spacing or paragraph spacing or any other thing related to this in app.
Any kind of link, idea, code, dock is welcomed...
You can have multiple NSMutableParagraphStyle in the one NSAttributedStrings by using the range attributes - just like you've already done.
You'll just have to detect where you want each NSMutableParagraphStyle and apply with various NSRange. That's the "fun" part.

How to increase spacing between lines in UITextView

How to increase spacing between lines in UITextView?
I wish to use default system font,i.e., Helvetica with size 15.
Declare you implement the protocol by adding
<NSLayoutManagerDelegate>
to your interface. Then, set:
yourTextView.layoutManager.delegate = self;
Then override this delegate method:
- (CGFloat)layoutManager:(NSLayoutManager *)layoutManager lineSpacingAfterGlyphAtIndex:(NSUInteger)glyphIndex withProposedLineFragmentRect:(CGRect)rect
{
return 5; // Line spacing of 19 is roughly equivalent to 5 here.
}
UPDATE:
I recently discovered that this can also be done using the NSMutableParagraphStyle setLineSpacing: API.
In an effort to always provide useful copy-paste code-snippet awesomeness, here you go!
NSMutableParagraphStyle *myStyle = [[NSMutableParagraphStyle alloc] init];
[myStyle setLineSpacing:myLineSpacingInt];
[myString addAttribute:myDesiredAttribute value:myStyle range:myDesiredRange];
[myViewElement setAttributedText:myString];
^myViewElement can be a UITextField, UILabel, or UITextView.
In IOS6+ you can set the typing attributes for a UITextView
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineSpacing:lineSpacing];
NSDictionary *attrsDictionary = [NSDictionary dictionaryWithObject:paragraphStyle forKey:NSParagraphStyleAttributeName];
[textView setTypingAttributes:attrsDictionary];

Resources