0

Sample project: http://d.pr/f/1coXu

I'm using TextKit to render some text into what is essentially a very basic recreation of UILabel. The code is very simple and in this example just draws a hardcoded NSAttributedString into the view itself:

class TextKitView: UIView {
    // TextKit Objects
    var textStorage: NSTextStorage!
    var textContainer: NSTextContainer!
    var layoutManager: NSLayoutManager!

    override init(frame: CGRect) {
        super.init(frame: frame)

        backgroundColor = UIColor.clearColor()

        layoutManager = NSLayoutManager()

        textStorage = NSTextStorage(attributedString: createAttributedString())
        textStorage.addLayoutManager(layoutManager)

        textContainer = NSTextContainer(size: CGSize(width: bounds.width, height: bounds.height))
        layoutManager.addTextContainer(textContainer)
    }

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

    override func drawRect(rect: CGRect) {
        let glyphRange = layoutManager.glyphRangeForTextContainer(textContainer)
        layoutManager.drawBackgroundForGlyphRange(glyphRange, atPoint: bounds.origin)
        layoutManager.drawGlyphsForGlyphRange(glyphRange, atPoint: bounds.origin)
    }

    private func createAttributedString() -> NSAttributedString {
        let attributedString = NSMutableAttributedString(string: "Test string for testing", attributes: [NSForegroundColorAttributeName: UIColor.blackColor(), NSFontAttributeName: UIFont.systemFontOfSize(16.0)])

        let labelAttributedString = NSAttributedString(string: "Foo bar\n testing", attributes: [NSForegroundColorAttributeName: UIColor.darkGrayColor(), NSBackgroundColorAttributeName: UIColor(white: 0.95, alpha: 1.0)])
        attributedString.appendAttributedString(labelAttributedString)

        return attributedString
    }
}

However, when I create the view:

override func viewDidLoad() {
    super.viewDidLoad()

    let textKitView = TextKitView(frame: CGRect(x: 0.0, y: 100.0, width: 320.0, height: 320.0))
    view.addSubview(textKitView)
}

It ends up looking like this:

enter image description here

Where you can see for some inexplicable reason the second line's background color and height is significantly shorter than the first, which looks really weird.

How do I prevent this? What's causing this? If I use UILabel and provide the same attributed string both lines are the same height. I've attached a very minimal sample project above if it helps.

Doug Smith
  • 29,668
  • 57
  • 204
  • 388
  • I don't understand the question. "Foo bar testing" is all the same size. The background color height in the first line is because the line also includes some bigger text so its height is bigger; to prove this, eliminate the "Test string for testing" part. Or notice how the bottom of the first-line background color matches perfectly the "g" descender in "Test string for testing". – matt Jul 01 '16 at 04:10
  • @matt Okay, phrased differently then, how do I make the height consistent regardless of the content of the line? – Doug Smith Jul 01 '16 at 04:31
  • With the relatively high level code (vs the bowels of TextKit), your only recourse might be to ensure every line includes white space of the necessary larger font size – Feldur Jul 01 '16 at 07:23

1 Answers1

1

Check out NSParagraphStyle: https://developer.apple.com/reference/uikit/nsparagraphstyle

There are line height properties on that class, i.e. minimumLineHeight and maximumLineHeight that may accomplish what you're trying to do. You can set the paragraph style for an NSAttributedString like so:

let paraStyle = NSMutableParagraphStyle()
paraStyle.setParagraphStyle = NSParagraphStyle.default
paraStyle.minimumLineHeight = 50 // for example
attributedString.addAttribute(NSParagraphStyleName, value: paraStyle, range:NSMakeRange(0, attributedString.length))
Dave Weston
  • 6,527
  • 1
  • 29
  • 44