iphone UITextView set line spacing

To change line spacing:

NSString *textViewText =self.myTextView.text;

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:textViewText];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineSpacing = 30;
NSDictionary *dict = @{NSParagraphStyleAttributeName : paragraphStyle };
[attributedString addAttributes:dict range:NSMakeRange(0, [textViewText length])];

self.myTextView.attributedText = attributedString;

With Swift 4 and iOS 11, according to your needs, you can choose one of the 3 following implementations in order to solve your problem.


#1. Using String and UIFontDescriptorSymbolicTraits traitLooseLeading property

traitLooseLeading has the following declaration:

The font uses looser leading values.

static var traitLooseLeading: UIFontDescriptorSymbolicTraits { get }

The following code shows how to implement traitLooseLeading in order to have a looser font leading for your UItextView.

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let textView = UITextView()
        view.addSubview(textView)

        textView.text = """
        Lorem ipsum
        Dolor sit amet,
        consectetur adipiscing elit
        """

        if let fontDescriptor = UIFontDescriptor
            .preferredFontDescriptor(withTextStyle: UIFontTextStyle.body)
            .withSymbolicTraits(UIFontDescriptorSymbolicTraits.traitLooseLeading) {
            let looseLeadingFont = UIFont(descriptor: fontDescriptor, size: 0)
            textView.font = looseLeadingFont
        }

        // Layout textView
        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.topAnchor.constraint(equalTo: view.readableContentGuide.topAnchor).isActive = true
        textView.bottomAnchor.constraint(equalTo: view.readableContentGuide.bottomAnchor).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor).isActive = true
        textView.trailingAnchor.constraint(equalTo: view.readableContentGuide.trailingAnchor).isActive = true
    }

}

#2. Using NSAttributedString and NSMutableParagraphStyle lineSpacing property

lineSpacing has the following declaration:

The distance in points between the bottom of one line fragment and the top of the next.

var lineSpacing: CGFloat { get set }

The following code shows how to implement lineSpacing in order to have a specific line spacing for some attributed text in your UItextView.

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let string = """
        Lorem ipsum
        Dolor sit amet,
        consectetur adipiscing elit
        """

        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = 15

        let attributes: [NSAttributedStringKey: Any] = [NSAttributedStringKey.paragraphStyle: paragraphStyle]
        let attributedString = NSAttributedString(string: string, attributes: attributes)

        let textView = UITextView()
        textView.attributedText = attributedString
        view.addSubview(textView)

        // Layout textView
        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.topAnchor.constraint(equalTo: view.readableContentGuide.topAnchor).isActive = true
        textView.bottomAnchor.constraint(equalTo: view.readableContentGuide.bottomAnchor).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor).isActive = true
        textView.trailingAnchor.constraint(equalTo: view.readableContentGuide.trailingAnchor).isActive = true
    }

}

#3. Using String and NSLayoutManagerDelegate protocol layoutManager(_:lineSpacingAfterGlyphAt:withProposedLineFragmentRect:) method

layoutManager(_:lineSpacingAfterGlyphAt:withProposedLineFragmentRect:) has the following declaration:

Returns the spacing after the line ending with the given glyph index. [...] This message is sent while each line is laid out to enable the layout manager delegate to customize the shape of line.

optional func layoutManager(_ layoutManager: NSLayoutManager, lineSpacingAfterGlyphAt glyphIndex: Int, withProposedLineFragmentRect rect: CGRect) -> CGFloat

The following code shows how to implement layoutManager(_:lineSpacingAfterGlyphAt:withProposedLineFragmentRect:) in order to have a specific line spacing for your UItextView.

import UIKit

class ViewController: UIViewController, NSLayoutManagerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        let textView = UITextView()
        textView.layoutManager.delegate = self
        view.addSubview(textView)

        textView.text = """
        Lorem ipsum
        Dolor sit amet,
        consectetur adipiscing elit
        """

        // Layout textView
        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.topAnchor.constraint(equalTo: view.readableContentGuide.topAnchor).isActive = true
        textView.bottomAnchor.constraint(equalTo: view.readableContentGuide.bottomAnchor).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor).isActive = true
        textView.trailingAnchor.constraint(equalTo: view.readableContentGuide.trailingAnchor).isActive = true
    }

    // MARK: - NSLayoutManagerDelegate

    func layoutManager(_ layoutManager: NSLayoutManager, lineSpacingAfterGlyphAt glyphIndex: Int, withProposedLineFragmentRect rect: CGRect) -> CGFloat {
        return 15
    }

}

As an alternative to the previous code, the following code shows how to implement layoutManager(_:lineSpacingAfterGlyphAt:withProposedLineFragmentRect:) in a UITextView subclass.

import UIKit

class LineSpacingTextView: UITextView, NSLayoutManagerDelegate {

    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)
        layoutManager.delegate = self
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    // MARK: - NSLayoutManagerDelegate

    func layoutManager(_ layoutManager: NSLayoutManager, lineSpacingAfterGlyphAt glyphIndex: Int, withProposedLineFragmentRect rect: CGRect) -> CGFloat {
        return 15
    }

}
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let textView = LineSpacingTextView()
        view.addSubview(textView)

        textView.text = """
        Lorem ipsum
        Dolor sit amet,
        consectetur adipiscing elit
        """

        // Layout textView
        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.topAnchor.constraint(equalTo: view.readableContentGuide.topAnchor).isActive = true
        textView.bottomAnchor.constraint(equalTo: view.readableContentGuide.bottomAnchor).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor).isActive = true
        textView.trailingAnchor.constraint(equalTo: view.readableContentGuide.trailingAnchor).isActive = true
    }

}

A look at the documentation for UITextView is sufficient to determine that changing the line spacing is not supported by that control.

For iOS 6 and above:

There is a possibility, using NSParagraphStyle,

NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineHeightMultiple = 50.0f;
paragraphStyle.maximumLineHeight = 50.0f;
paragraphStyle.minimumLineHeight = 50.0f;
NSString *string = @"your paragraph here";
NSDictionary *attribute = @{
   NSParagraphStyleAttributeName : paragraphStyle, 
   };
[textview setFont:[uifont fontwithname:@"Arial" size:20.0f]];
textview.attributedText = [[NSAttributedString alloc] initWithString:string attributes:attribute];

Well now on iOS6, there is a possibility, using NSParagraphStyle, but it is very poorly documented and seems to work seldomly.

I'm currently working about it like this:

UITextView *lab = [LocalTexts objectAtIndex:j];

NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineHeightMultiple = 50.0f;
paragraphStyle.maximumLineHeight = 50.0f;
paragraphStyle.minimumLineHeight = 50.0f;

NSString *string = lab.text;
NSDictionary *ats = @{
    NSFontAttributeName: [UIFont fontWithName:@"DIN Medium" size:16.0f],
    NSParagraphStyleAttributeName: paragraphStyle, 
};

lab.attributedText = [[NSAttributedString alloc] initWithString:string attributes:ats];

Problem is that when you set the Font, the line height stops working. Very odd. I haven't found a fix for it yet.

Also you can create a custom Attributed CoreText view... but it's a bit more technical, you can find a demo of how it is done here

Well I hope something helps.