IPhone: Change line spacing in UITextView? - iphone

I've been looking all over the 'net for information/examples...
I'm trying to change the line spacing of text inside a UITextView object to double spaced. I thought you could do it via Core Text, but haven't found a solution!
Any example code or information would be greatly appreciated! Thanks!

You don't have to look all over the net. A look at the documentation for UITextView is sufficient to determine that changing the line spacing is not supported by that control.
With Core Text you have complete control over the layout of the text you draw, of course. But it would be a lot of work to rewrite a UITextView-like control from scratch.

This question was asked before iOS 6. I'd like to post an updated answer for those who would like a way to do this.
This can be done now with iOS 6 and later by using an NSAttributedString. UITextView now accepts an attributed string as one of its properties. You can do all sorts of text manipulation with attributed strings, including line spacing. You can set the min and max line heights for the paragraph style attribute of the string.
Check out the NSAttributedString Class Reference for more information.
Here's a sample of what you could do:
NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init];
paragraph.minimumLineHeight = 21.0f;
paragraph.maximumLineHeight = 21.0f;
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:#"Test text line 1\nTest text line 2\nTest text line 3" attributes:#{NSParagraphStyleAttributeName: paragraph}];
textView.attributedText = attributedString;

You can use NSLayoutManagerDelegate. Add that delegate to your ViewController or UIView class (etc.) and then when you create your UITextView...
yourTextView.layoutManager.delegate = self
Add this delegate method:
func layoutManager(layoutManager: NSLayoutManager, lineSpacingAfterGlyphAtIndex glyphIndex: Int, withProposedLineFragmentRect rect: CGRect) -> CGFloat {
return 5 //Whatever you'd like...
}

Related

Justify Text in UILabel iOS

I am having a problem that in iOS I am using UILabel to display 2,3 line text, I want to align text as justified but I am not finding any option to do so. Any suggestions how to make justify text in label?
i put these line to make start it from top
CGSize maximumSize = CGSizeMake(300, 9999);
NSString *textString = someString;
UIFont *textFont = [UIFont fontWithName:#"Futura" size:14];
CGSize textStringSize = [textString sizeWithFont:textFont
constrainedToSize:maximumSize
lineBreakMode:text.lineBreakMode];
CGRect textFrame = CGRectMake(10, 110, 300, textStringSize.height);
text.frame = textFrame;
so any trick like this to make it justfiy
Thanks
There is now a convenient way to justify text since iOS6. You can create an instance of NSAttributedString, set appropriate properties and assign this attributed string to a text representing view such as UILabel, UITextView, etc. It's easy as this:
Create an instance of NSMutableParagraphStyle and set its properties.
NSMutableParagraphStyle *paragraphStyles = [[NSMutableParagraphStyle alloc] init];
paragraphStyles.alignment = NSTextAlignmentJustified; //justified text
paragraphStyles.firstLineHeadIndent = 10.0; //must have a value to make it work
Create NSDictionary for text attributes and create attributed string.
NSDictionary *attributes = #{NSParagraphStyleAttributeName: paragraphStyles};
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString: string attributes: attributes];
Set attributed string to a label.
existingLabel.attributedText = attributedString;
Can't be done I'm afraid - well not with UILabel.
You can use the UIWebView or a 3rd party library such as OHAttributedLabel
Happy Coding :)
Update:
This answer has been obsolete since iOS6. Please refer to Tankista's answer.
As mentionned by #martin, my class OHAttributedLabel can make this very easily.
(You will find it on my github and also find plenty of references to it on SO as well)
It can be done easily, but you need to use Core Text.
subclass a UIView, add an NSString property, create an NSAttributedString and pass kCTJustifiedTextAlignment value for the kCTParagraphStyleSpecifierAlignment key, then draw the NSAttributedString using Quartz or CoreText in your drawrect method.
edit: kCTParagraphStyleSpecifierAlignment key kCTJustifiedTextAlignment value should be used to create a CTParagraphStyleRef struct and passed in as a value for kCTParagraphStyleAttributeName key when creating the NSAttributedString.
SWIFT 4.x
version of approved answer:
Create an instance of NSMutableParagraphStyle and set its properties.
let justifiedParagraphStyles: NSMutableParagraphStyle = NSMutableParagraphStyle.init()
justifiedParagraphStyles.alignment = .justified //justified text
justifiedParagraphStyles.firstLineHeadIndent = 10.0 //must have a value to make it work
Create NSDictionary for text attributes and create attributed string.
let attributes = [NSAttributedStringKey.paragraphStyle: justifiedParagraphStyles]
let attributedString = NSAttributedString.init(string: string, attributes: attributes)
Set attributed string to a label.
existingLabel.attributedText = attributedString

Set line height in UITextView

I'm already pretty sure that it can't be done with any public API, but I still want to ask:
Is there any way to change the line height in a UITextView?
Would be enough to do it statically, no need to change it at runtime. The problem is that the default line height is just WAY too small. Text will look extremely compressed and is a nightmare when trying to write longer texts.
thanks,
Max
EDIT: I know that there is UIWebView and that it's nice and can do styling etc. But it's not editable. I need a editable text component with acceptable line height. That thing from the Omni Frameworks doesn't help either, as it's too slow and doesn't feel right...
After iOS 7, the styleString approach no longer works.
Two new alternatives are available.
Firstly, TextKit; a powerful new layout engine. To change line spacing, set the UITextView's layout manager's delegate:
textView.layoutManager.delegate = self; // you'll need to declare you implement the NSLayoutManagerDelegate protocol
Then override this delegate method:
- (CGFloat)layoutManager:(NSLayoutManager *)layoutManager lineSpacingAfterGlyphAtIndex:(NSUInteger)glyphIndex withProposedLineFragmentRect:(CGRect)rect
{
return 20; // For really wide spacing; pick your own value
}
Secondly, iOS 7 now supports NSParagraphStyle's lineSpacing. This gives even more control, e.g. first line indentation, and calculation of a bounding rect. So alternatively...
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.headIndent = 15; // <--- indention if you need it
paragraphStyle.firstLineHeadIndent = 15;
paragraphStyle.lineSpacing = 7; // <--- magic line spacing here!
NSDictionary *attrsDictionary =
#{ NSParagraphStyleAttributeName: paragraphStyle }; // <-- there are many more attrs, e.g NSFontAttributeName
self.textView.attributedText = [[NSAttributedString alloc] initWithString:#"Hello World over many lines!" attributes:attrsDictionary];
FWIW, the old contentInset method to align the text along the left edge of UITextView is also no use under iOS7. Instead, to remove the margin:
textView.textContainer.lineFragmentPadding = 0;
Note: this is not available in iOS7:
I have discovered that you can create a subclass that re-implements [UITextView styleString]:
#interface UITextView ()
- (id)styleString; // make compiler happy
#end
#interface MBTextView : UITextView
#end
#implementation MBTextView
- (id)styleString {
return [[super styleString] stringByAppendingString:#"; line-height: 1.2em"];
}
#end
This is not private API usage: it is just subclassing. It's possible Apple may disagree of course (though considering how we all used to swizzle everything in order to customize UIKit appearance, I feel that this kind of “private” usage is not what Apple object to), but it's such an easy way to achieve the goals of this question that you may as well try it. Should the app be rejected you can spend the (probably significant) time on a more difficult solution.
In the Attribute Inspector for the UITextView instead change the property Text to Attributed (from Plain), and click the "more" button, there you can set the line height and spacing.
The only solution we've found and the one we've chosen: create a custom font. Sound silly but seems to be the only realistic way.
The UITextView subclass override of styleString only works if you define a category on UITextView that defines styleString, otherwise you get a compile error. For example, in your UITextView subclass:
#import "SomeDangTextView.h"
#interface UITextView ()
- (id)styleString;
#end
#implementation SomeDangTextView
- (id)styleString {
return [[super styleString] stringByAppendingString:#"; line-height: 1.5em"];
}
#end
This question is almost 10 years old but this is how it's done:
Just implement the following method of UITextViewDelegate and set your attributes:
let textViewAttributes: [NSAttributedString.Key:Any] = [
.font: UIFont.systemFont(ofSize: 15, weight: .medium),
.foregroundColor: UIColor.black,
.paragraphStyle: {
let paragraph = NSMutableParagraphStyle()
paragraph.lineSpacing = 4
return paragraph
}()
]
func textViewDidBeginEditing(_ textView: UITextView) {
textView.typingAttributes = textViewAttributes
}
It's important to add these attributes on textViewDidBeginEditing as the dictionary gets reset every time the text selection changes. More info can be found on the official documentation.
According to Apple's Documentation you can use a UIWebView.
This class does not support multiple styles for text. The font, color, and text alignment attributes you specify always apply to the entire contents of the text view. To display more complex styling in your application, you need to use a UIWebView object and render your content using HTML.
This class does not support multiple styles for text. The font, color, and text alignment attributes you specify always apply to the entire contents of the text view. To display more complex styling in your application, you need to use a UIWebView object and render your content using HTML.
Use OHAttributedLabel Lib. This will solve all the problem you mentioned.

UITextView.text property doesn't update first time, and then clips or doesn't display when it does

I'm trying to get the contents from a dictionary into a UITextView. The dictionary contains molecular masses paired with percentages, for example:
24 -> 98
25 -> 1.9
26 -> 0.1
I have an NSArray containing the keys from the dictionary, sorted in ascending order. So, here is my code to generate the string to set as the textField.text property:
-(void)detailIsotopes:(NSMutableDictionary *)isotopes withOrder:(NSMutableArray *)order{
NSMutableString *detailString = [[NSMutableString alloc] init];
for (NSNumber *mass in order){
[detailString appendString:[NSString stringWithFormat:#"%d: %f\n", [mass integerValue], [[isotopes valueForKey:[NSString stringWithFormat:#"%#", mass]] floatValue]]];
}
NSLog(#"%#", detailString);
textField.text = detailString;
[detailString release];
}
This should create a string looking like this:
24: 89
25: 1.9
26: 0.1
For some reason, this method never does anything the first time it runs. I see the NSLog output, which outputs the correct string. However, the contents of the UITextView don't change: they stay as 'Lorem ipsum dolor sit amet...' from Interface Builder. If I run the method again, it works, sort of.
The UITextView displays some of the text, and then just cuts off half way through a line, leaving only the tops of the characters. If I delete the contents above the half line, the other lines pull up from under the divide: the contents are there, they just stop being shown, if you understand what I mean. This appears to go away if I enable paging in the view. If I do that, then the line isn't truncated, but the UITextView just stops showing any content after some point, although the scroll bar indicates that there is more to go (which there is).
The view containing the UITextView is not visible when the contents is set, if that makes a difference. A separate view controller generates the NSMutableDictionary and NSMutableArray and sends them to its delegate, which then sends them to the view which should display the UITextField and has the detailIsotopes: withOrder: method. The two can be swapped between with an info button.
Does anyone understand why these things are happening?
Thanks for any advice you can give!
First of all, I don't think you need to allocate and release your NSMutableString here. Simply initialize one using [NSMutableString string] which creates an empty string you can modify and don't need to explicitly release.
Second thing, you seem to store masses in NSStrings in your NSDictionnary, why do you use their integerValue method for stringWithFormat (with %d modifier), instead of using them as is? (the stringWithFormat modifier for NSStrings is %#)
Also, you talk about a UITextView at start, then about a UITextField, are you sure you did not make a mistake somewhere? I guess the receiving object for your formatted NSString should rather be the UITextView (if you have both a textField and textView).
If it's not about this, maybe you are calling detailIsotopes too early and the textView it's created yet. Try to NSLog its address and see if it's nil the first time. It could be the case if you use Interface Builder and your UITextField is an ib outlet. If you do, then you could store your dictionary and array in the viewController, and set the textField in the viewController's viewDidLoad method. Or call detailIsotopes after you've displayed the view, I guess that's up to you.
About the truncated text, I think that's because UITextView doesn't resize itself automatically, so it keeps the height you originally set. What I usually do is this:
CGRect frame = textView.frame;
frame.size.height = textView.contentSize; // you can adjust this to leave some space at the end
textView.frame = frame;
This will set the textView height to the content (the text) height.
Also note that if your textView is supposed to display the whole text, you can set its scrollingEnabled property to FALSE so it never allows scrolling.
Hope that helps.

iPhone:How to add "Degree" symbol in UILabel string text?

I want to include "degree" symbol for weather report as 45 degree C. How to add degree symbol in string to include that UILabel?
If anybody knows it, please share to me.
Thank you.
Shift-option-8?
In Swift
cell.lblTemperature.text = NSString(format:"23%#", "\u{00B0}") as String
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:#"80\u00b0c"];
[attributedString setAttributes:#{NSFontAttributeName : [UIFont fontWithName:#"Helvetica-light" size:10.0]
, NSBaselineOffsetAttributeName : #22} range:NSMakeRange(2, 2)];
//asign this as a
examplelabel.attributedtext = attributedString;
In Xcode 8.0:
Press Control+Command+Space Bar or Xcode->Edit->Emoji & Symbols, later search the degree symbols from pop-up screen.
You can easily add UILabel or TextView components.

What is the best way to display long file name in UITablView

I have some source codes to display all file names in a UITablView
I noticed that if the file name too long, for example filenameabcdefghklmn.dat it will display filenameabcde...
I hope to know what is the best way to display long file name in UITablView?
Thanks
interdev
You can set the label properties of the label in which you are entering text like:
[lbl setNumberOfLines:0];
[lbl setLineBreakMode:UILineBreakModeCharacterWrap];
Now this will show the file name in the next line if the file name did not fit in one line.
You need to adjust the label height also.
Hope this helps,
Thanks,
Madhup
Customise your table cell and draw the string directly to the table cell's view.
You can use sizeWithFont:constrainedToSize: to figure out how big your string will be so you can size your cell appropriately.
This post may help you out:
http://www.ubergeek.tv/article.php?pid=143
Allow rotation to landscape mode. Or use a smaller font. Or just let the label get abbreviated with the "..." ellipsis.
There isn't a heck of a lot you can do here.
Show long name in two line in same row...
like
if([myString length] > MAX)
{
myString1 = [myString substringToIndex:MAX];
cell.textLabel.text = myString1;
mystring2 = [myString substringFromIndex:MAX];
cell.detailTextLabel.text = mystring2;
}
You can use
cell.textLabel.numberOfLines=3;
cell.textLabel.lineBreakMode=UILineBreakModeWordWrap;
Put this code in your cellForRowAtIndexPath tableview delegate methods.