5

I am trying to set the line spacing in a UILabel as specified by Mike Slutsky here. It works correctly for the text I specify from the Storyboard. When I try to set the UILabel.text in code, it reverts back to the default line spacing. Can someone help me understand how to either:

  1. Keep it from reverting to default, and use the settings I specified on the Storyboard or

  2. Set the value in code.

I've seen a lot of examples around using NSAttribute and NSParagraph, but since it's now possible to set in the Storyboard, I would expect their may be a more straightforward answer. Many thanks for the help!

I set the "Height Multiple" as illustrated in the above link, and my only code is as follows:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var textView: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        textView.text = "Some example text"
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

If I remove the textView.text line, it displays correctly, otherwise it's set back to the default line spacing (or Height Multiple).

Krunal
  • 77,632
  • 48
  • 245
  • 261
Robert
  • 1,499
  • 2
  • 14
  • 22
  • Not a whole lot of code to show, but i've added it. Thanks for the suggestion. – Robert May 22 '15 at 01:11
  • Very helpful, actually! This gives me a much better idea what the issue is. I think I can answer based on that. – matt May 22 '15 at 01:13
  • 3
    When you set `textView.text` that resets the attributed text. Set `textView.attributedText` instead, and use an `NSAttributedString` every time. – i_am_jorf May 22 '15 at 01:16

4 Answers4

11

Here's what's going on. You set things up in the storyboard with custom line spacing. This means, even though you may not know it, that in the storyboard you have set the label's attributedText.

But if you then come along and set the label's text in code, as you are doing, you throw away the attributedText and therefore all the attributes that it had. That is why, as you rightly say, things revert to the default look of the label.

The solution is: instead of setting the label's text, set its attributedText. In particular, fetch the label's existing attributedText; assign it into an NSMutableAttributedString so you can change it; replace its string while keeping the attributes; and assign it back to the label's attributedText.

So for example (I have called my label lab - your textView is a bad choice, as a text view is whole different animal):

let text = self.lab.attributedText
let mas = NSMutableAttributedString(attributedString:text)
mas.replaceCharactersInRange(NSMakeRange(0, count(mas.string.utf16)), 
    withString: "Little poltergeists make up the principle form of material manifestation")
self.lab.attributedText = mas
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • That makes total sense. Thanks for the reply and for the code! I'm getting the error **utf16Count' is unavailable: Take the count of a UTF-16 view instead, i.e. count(str.utf16)**, but i'm researching a solution to that. Thanks again – Robert May 22 '15 at 01:54
  • You're right, I tested under an old version of Xcode. Sorry about that. – matt May 22 '15 at 03:45
  • Fixed now, sorry about that. – matt May 22 '15 at 03:50
  • I knew you'd like it. Notice that this simply imposes the attributes of the _first character_ of the old text onto the new text. This may work in your simple case, because the first character's attributes include the paragraph attributes and font attributes you are interested in; but if your attributes were more complicated, you'd need more complicated code. – matt May 22 '15 at 14:59
1

UILabel has

@property(nonatomic, copy) NSAttributedString *attributedText since iOS 6.0,

This property is nil by default. Assigning a new value to this property also replaces the value of the text property with the same string data, albeit without any formatting information. In addition, assigning a new a value updates the values in the font, textColor, and other style-related properties so that they reflect the style information starting at location 0 in the attributed string.

If you set textView.text = "Some example text" again, you will loose your attributes. You should only pick one of them and not switching between them if you are sure what you are doing

Wingzero
  • 9,644
  • 10
  • 39
  • 80
1

Here is @matt 's answer in Obj. C:

  NSMutableAttributedString *mas = [self.lab.attributedText mutableCopy];
  [mas replaceCharactersInRange:NSMakeRange(0, [mas.string length]) 
    withString:@"Little poltergeists make up the principle form of material manifestation"]; 
  self.lab.attributedText = mas;

Hope this helps someone!

user2253546
  • 575
  • 1
  • 8
  • 18
1

Swift 3 Just copy & execute this code to see result

let label = UILabel()
let stringValue = "UILabel\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
Krunal
  • 77,632
  • 48
  • 245
  • 261