How to set a space between characters and lines in UILabel - ios

I'd like set one spacing between first and second lines, between other lines need another spacing. With this, second and next lines must have specific character spacing.
This all need doing in one control. How i can do this? I decided to create a separate UILabel for each row but i think it's wrong way.

You can't change the spacing between lines of text, you will have to subclass UILabel and roll your own drawTextInRect, create multiple labels, or use a different font.
But there are two custom Labels, that allow you to control the lineheight.
1) https://github.com/LemonCake/MSLabel
2) https://github.com/Tuszy/MTLabel
Hope this helps...
In iOS6, you could do this:
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineSpacing:40];
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [labelText length])];
cell.label.attributedText = attributedString ;

Try this, it should work for you (with Swift 4)
let label = UILabel()
let stringValue = "How to\ncontrol\nthe\nline spacing\nin UILabel"
let attrString = NSMutableAttributedString(string: stringValue)
var style = NSMutableParagraphStyle()
style.lineSpacing = 24 // change line spacing between paragraph like 36 or 48
style.minimumLineHeight = 20 // change line spacing between each line like 30 or 40
attrString.addAttribute(NSAttributedStringKey.paragraphStyle, value: style, range: NSRange(location: 0, length: stringValue.characters.count))
// add strike
attrString.addAttribute(NSAttributedStringKey.strikethroughStyle, value: 2, range: NSMakeRange(0, attrString.length))
// add space between characters
attrString.addAttribute(NSAttributedStringKey.kern, value: 2, range: NSMakeRange(0, attrString.length))
label.attributedText = attrString
Result:

Related

Is there no way to decrease line spacing on a UILabel's text? [duplicate]

I want to have two lines of text appear really close together (small line spacing) for a button. I have the following code:
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:#"50 WPM"];
NSMutableParagraphStyle *paragrapStyle = [[NSMutableParagraphStyle alloc] init];
paragrapStyle.alignment = NSTextAlignmentCenter;
paragrapStyle.lineSpacing = -10;
[string addAttribute:NSParagraphStyleAttributeName value:paragrapStyle range:NSMakeRange(0, string.length)];
UIFont *font1 = [UIFont systemFontOfSize:22.0];
[string addAttribute:NSFontAttributeName value:font1 range:NSMakeRange(0, string.length - 4)];
UIFont *font = [UIFont systemFontOfSize:15.0];
[string addAttribute:NSFontAttributeName value:font range:NSMakeRange(string.length - 3, 3)];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor greenColor] range:NSMakeRange(0, string.length)];
[self.button setAttributedTitle:string forState:UIControlStateNormal];
But as linespacing can't be negative, it doesn't get nearly as close as I'd like it to be. It looks like this:
Is there any way to get them closer?
Well if you have an attribute string then everything should be possible. :) You just have to look more.
- (void)setMinimumLineHeight:(CGFloat)aFloat
- (void)setMaximumLineHeight:(CGFloat)aFloat
Try
[paragraphStyle setLineSpacing:0.0f];
[paragraphStyle setMaximumLineHeight:7.0f];
You will realise that maximumLineHeight is not maximumLineSpacing. ^^
This for example is with setMaximumLineHeight:12];
Here a little extension in Swift3 which supports negative lineSpacing
extension UILabel {
func set(lineSpacing: CGFloat, textAlignment: NSTextAlignment = NSTextAlignment.center) {
if let text = self.text {
let paragraphStyle = NSMutableParagraphStyle()
if lineSpacing < 0 {
paragraphStyle.lineSpacing = 0
paragraphStyle.maximumLineHeight = self.font.pointSize + lineSpacing
} else {
paragraphStyle.lineSpacing = lineSpacing
}
let attrString = NSMutableAttributedString(string: text)
attrString.addAttribute(NSParagraphStyleAttributeName, value:paragraphStyle, range:NSMakeRange(0, attrString.length))
self.attributedText = attrString
self.textAlignment = textAlignment
}
}
}
I would suggest reading up on TextKit that was introduced in iOS7. I do not have much experience from it, but I do know that it gives you a lot of possibilities when it comes to attributing your texts.
In Swift 3, you can achieve this by :
let paragraph = NSMutableParagraphStyle()
paragraph.lineSpacing = 0
paragraph.maximumLineHeight = 20.
Keep the lineSpacing = 0. You can adjust the maximumLineHeight to make it closer or to increase the spacing.
How about subclassing UIButton, and add 2 UILabels to the buttons view that are close together. Create properties for the labels and set approrpietly:
CustomButton *btn = [CustomButton new];
btn.textLine1 = #"Top";
btn.textLine2 = #"Bottom";
The only problem doing it this way is you will need to handle the text color when the state changes yourself.

How to add spacing to lines in NSAttributedString

I am making an app that formats screenplays, I am using a NSAttributedString to format the text entered into a UITextView, but some of the lines are too close together.
I was wondering if anyone could provide a code example or a tip on how to alter the margin between these lines so there is more space between them.
Below is an image of another desktop screenwriting program that demonstrates what I mean, notice how there is a bit of space before each bit where it says "DOROTHY".
The following sample code uses paragraph style to adjust spacing between paragraphs of a text.
UIFont *font = [UIFont fontWithName:fontName size:fontSize];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.paragraphSpacing = 0.25 * font.lineHeight;
NSDictionary *attributes = #{NSFontAttributeName:font,
NSForegroundColorAttributeName:[UIColor whiteColor],
NSBackgroundColorAttributeName:[UIColor clearColor],
NSParagraphStyleAttributeName:paragraphStyle,
};
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text attributes:attributes];
To selectively adjust spacing for certain paragraphs, apply the paragraph style to only those paragraphs.
Hope this helps.
Great answer #Joe Smith
In case anyone would like to see what this looks like in Swift 2.*:
let font = UIFont(name: String, size: CGFloat)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.paragraphSpacing = 0.25 * font.lineHeight
let attributes = [NSFontAttributeName:font, NSParagraphStyleAttributeName:paragraphStyle]
let attributedText = NSAttributedString(string: String, attributes: attributes)
self.textView.attributedText = attributedText
Here is Swift 4.* version:
let string =
"""
A multiline
string here
"""
let font = UIFont(name: "Avenir-Roman", size: 17.0)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.paragraphSpacing = 0.25 * (font?.lineHeight)!
let attributes = [NSAttributedStringKey.font: font as Any, NSAttributedStringKey.paragraphStyle: paragraphStyle]
let attrText = NSAttributedString(string: string, attributes: attributes)
self.textView.attributedText = attrText

Really close lines with NSAttributedString?

I want to have two lines of text appear really close together (small line spacing) for a button. I have the following code:
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:#"50 WPM"];
NSMutableParagraphStyle *paragrapStyle = [[NSMutableParagraphStyle alloc] init];
paragrapStyle.alignment = NSTextAlignmentCenter;
paragrapStyle.lineSpacing = -10;
[string addAttribute:NSParagraphStyleAttributeName value:paragrapStyle range:NSMakeRange(0, string.length)];
UIFont *font1 = [UIFont systemFontOfSize:22.0];
[string addAttribute:NSFontAttributeName value:font1 range:NSMakeRange(0, string.length - 4)];
UIFont *font = [UIFont systemFontOfSize:15.0];
[string addAttribute:NSFontAttributeName value:font range:NSMakeRange(string.length - 3, 3)];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor greenColor] range:NSMakeRange(0, string.length)];
[self.button setAttributedTitle:string forState:UIControlStateNormal];
But as linespacing can't be negative, it doesn't get nearly as close as I'd like it to be. It looks like this:
Is there any way to get them closer?
Well if you have an attribute string then everything should be possible. :) You just have to look more.
- (void)setMinimumLineHeight:(CGFloat)aFloat
- (void)setMaximumLineHeight:(CGFloat)aFloat
Try
[paragraphStyle setLineSpacing:0.0f];
[paragraphStyle setMaximumLineHeight:7.0f];
You will realise that maximumLineHeight is not maximumLineSpacing. ^^
This for example is with setMaximumLineHeight:12];
Here a little extension in Swift3 which supports negative lineSpacing
extension UILabel {
func set(lineSpacing: CGFloat, textAlignment: NSTextAlignment = NSTextAlignment.center) {
if let text = self.text {
let paragraphStyle = NSMutableParagraphStyle()
if lineSpacing < 0 {
paragraphStyle.lineSpacing = 0
paragraphStyle.maximumLineHeight = self.font.pointSize + lineSpacing
} else {
paragraphStyle.lineSpacing = lineSpacing
}
let attrString = NSMutableAttributedString(string: text)
attrString.addAttribute(NSParagraphStyleAttributeName, value:paragraphStyle, range:NSMakeRange(0, attrString.length))
self.attributedText = attrString
self.textAlignment = textAlignment
}
}
}
I would suggest reading up on TextKit that was introduced in iOS7. I do not have much experience from it, but I do know that it gives you a lot of possibilities when it comes to attributing your texts.
In Swift 3, you can achieve this by :
let paragraph = NSMutableParagraphStyle()
paragraph.lineSpacing = 0
paragraph.maximumLineHeight = 20.
Keep the lineSpacing = 0. You can adjust the maximumLineHeight to make it closer or to increase the spacing.
How about subclassing UIButton, and add 2 UILabels to the buttons view that are close together. Create properties for the labels and set approrpietly:
CustomButton *btn = [CustomButton new];
btn.textLine1 = #"Top";
btn.textLine2 = #"Bottom";
The only problem doing it this way is you will need to handle the text color when the state changes yourself.

Objective c - Multiple colors in a label

What is the easiest way to have a label with different colors?
For example I want to present the message:
"John Johnson sent you a message"
But I want that John Johnson will be in blue color
and the rest of the message in black color.
You need the NSAttributedString class (or the mutable one - NSMutableAttributedString) in order to set attributes (for example, font and kerning) that apply to individual characters or ranges of characters in the string and a custom label control that can visualize NSAttributedString like TTTAttributedLabel.
In UILabel basically impossible. If you want to this you must override drawTextInRect should be executed. But I will recommend OHAttributedLabel. this is have a attributedString is a textcolor can be set to specify a range.
Use a UIWebView.
webView.text =
#"<span style:\"color:blue;\">John Johnson</span> sent you a message.";
Use CoreText. Hope this helps.
I created an UILabel extension to do this. Basically what it does is use NSAttributedString to define the color for some particular range: https://github.com/joaoffcosta/UILabel-FormattedText
If you wish to implement this behavior yourself, just do the following:
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithAttributedString: #"John Johnson sent you a message"];
[text addAttribute: NSFontAttributeName
value: font
range: range];
[self setAttributedText: text];
Try this with swift (execute code with following extension)
extension NSMutableAttributedString {
func setColorForText(textToFind: String, withColor color: UIColor) {
let range: NSRange = self.mutableString.range(of: textToFind, options: .caseInsensitive)
self.addAttribute(NSAttributedStringKey.foregroundColor, value: color, range: range)
}
}
Try an extension with UILabel:
let label = UILabel()
label.frame = CGRect(x: 40, y: 100, width: 280, height: 200)
let stringValue = "John Johnson sent you a message" // or direct assign single string value like "firstsecondthird"
label.textColor = UIColor.lightGray
label.numberOfLines = 0
let attributedString: NSMutableAttributedString = NSMutableAttributedString(string: stringValue)
attributedString.setColorForText(textToFind: "John Johnson", withColor: UIColor.blue)
label.font = UIFont.systemFont(ofSize: 26)
label.attributedText = attributedString
self.view.addSubview(label)
Here is result:

Set UILabel line spacing

How can I modify the gap between lines (line spacing) in a multiline UILabel?
Edit: Evidently NSAttributedString will do it, on iOS 6 and later. Instead of using an NSString to set the label's text, create an NSAttributedString, set attributes on it, then set it as the .attributedText on the label. The code you want will be something like this:
NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString:#"Sample text"];
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
[style setLineSpacing:24];
[attrString addAttribute:NSParagraphStyleAttributeName
value:style
range:NSMakeRange(0, strLength)];
uiLabel.attributedText = attrString;
NSAttributedString's old attributedStringWithString did the same thing, but now that is being deprecated.
For historical reasons, here's my original answer:
Short answer: you can't. To change the spacing between lines of text, you will have to subclass UILabel and roll your own drawTextInRect, create multiple labels, or use a different font (perhaps one edited for a specific line height, see Phillipe's answer).
Long answer: In the print and online world, the space between lines of text is known as "leading" (rhymes with 'heading', and comes from the lead metal used decades ago). Leading is a read-only property of UIFont, which was deprecated in 4.0 and replaced by lineHeight. As far as I know, there's no way to create a font with a specific set of parameters such as lineHeight; you get the system fonts and any custom font you add, but can't tweak them once installed.
There is no spacing parameter in UILabel, either.
I'm not particularly happy with UILabel's behavior as is, so I suggest writing your own subclass or using a 3rd-party library. That will make the behavior independent of your font choice and be the most reusable solution.
I wish there was more flexibility in UILabel, and I'd be happy to be proven wrong!
Starting in ios 6 you can set an attributed string in the UILabel:
NSString *labelText = #"some text";
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:labelText];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineSpacing:40];
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [labelText length])];
cell.label.attributedText = attributedString ;
You can control line spacing in the storyboard:
duplicate question
From Interface Builder:
Programmatically:
SWift 4
Using label extension
extension UILabel {
func setLineSpacing(lineSpacing: CGFloat = 0.0, lineHeightMultiple: CGFloat = 0.0) {
guard let labelText = self.text else { return }
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = lineSpacing
paragraphStyle.lineHeightMultiple = lineHeightMultiple
let attributedString:NSMutableAttributedString
if let labelattributedText = self.attributedText {
attributedString = NSMutableAttributedString(attributedString: labelattributedText)
} else {
attributedString = NSMutableAttributedString(string: labelText)
}
// Line spacing attribute
attributedString.addAttribute(NSAttributedStringKey.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attributedString.length))
self.attributedText = attributedString
}
}
Now call extension function
let label = UILabel()
let stringValue = "How to\ncontrol\nthe\nline spacing\nin UILabel"
// Pass value for any one argument - lineSpacing or lineHeightMultiple
label.setLineSpacing(lineSpacing: 2.0) . // try values 1.0 to 5.0
// or try lineHeightMultiple
//label.setLineSpacing(lineHeightMultiple = 2.0) // try values 0.5 to 2.0
Or using label instance (Just copy & execute this code to see result)
let label = UILabel()
let stringValue = "Set\nUILabel\nline\nspacing"
let attrString = NSMutableAttributedString(string: stringValue)
var style = NSMutableParagraphStyle()
style.lineSpacing = 24 // change line spacing between paragraph like 36 or 48
style.minimumLineHeight = 20 // change line spacing between each line like 30 or 40
// Line spacing attribute
attrString.addAttribute(NSAttributedStringKey.paragraphStyle, value: style, range: NSRange(location: 0, length: stringValue.characters.count))
// Character spacing attribute
attrString.addAttribute(NSAttributedStringKey.kern, value: 2, range: NSMakeRange(0, attrString.length))
label.attributedText = attrString
Swift 3
let label = UILabel()
let stringValue = "Set\nUILabel\nline\nspacing"
let attrString = NSMutableAttributedString(string: stringValue)
var style = NSMutableParagraphStyle()
style.lineSpacing = 24 // change line spacing between paragraph like 36 or 48
style.minimumLineHeight = 20 // change line spacing between each line like 30 or 40
attrString.addAttribute(NSParagraphStyleAttributeName, value: style, range: NSRange(location: 0, length: stringValue.characters.count))
label.attributedText = attrString
My solution was to patch the font file itself and fix its line height definitely.
http://mbauman.net/geek/2009/03/15/minor-truetype-font-editing-on-a-mac/
I had to modify 'lineGap', 'ascender', 'descender' in the 'hhea' block (as in the blog example).
This guy created a class to get line-height (without using CoreText, as MTLabel library) : https://github.com/LemonCake/MSLabel
Best thing I found is: https://github.com/mattt/TTTAttributedLabel
It's a UILabel subclass so you can just drop it in, and then to change the line height:
myLabel.lineHeightMultiple = 0.85;
myLabel.leading = 2;
I've found 3rd Party Libraries Like this one:
https://github.com/Tuszy/MTLabel
To be the easiest solution.
Here's some swift-code for you to set the line spacing programmatically
let label = UILabel()
let attributedText = NSMutableAttributedString(string: "Your string")
let paragraphStyle = NSMutableParagraphStyle()
//SET THIS:
paragraphStyle.lineSpacing = 4
//OR SET THIS:
paragraphStyle.lineHeightMultiple = 4
//Or set both :)
let range = NSMakeRange(0, attributedText.length)
attributedText.addAttributes([NSParagraphStyleAttributeName : paragraphStyle], range: range)
label.attributedText = attributedText
Of course, Mike's answer doesn't work if you pass the string programmatically. In this case you need to pass a attributed string and change it's style.
NSMutableAttributedString * attrString = [[NSMutableAttributedString alloc] initWithString:#"Your \nregular \nstring"];
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
[style setLineSpacing:4];
[attrString addAttribute:NSParagraphStyleAttributeName
value:style
range:NSMakeRange(0, attrString.length)];
_label.attributedText = attrString;

Resources