0

How can I calculate UITextView first baseline position?

enter image description here

I tried calculating it this way:

self.textView.font!.descender + self.textView.font!.leading

However, the value I'm getting is not correct. Any ideas, hints?

Rafa de King
  • 37,274
  • 22
  • 102
  • 134
  • `descender` if the offset from the baseline, certainly it should not been involved in the calculation. `leading` or `lineHeight` *might* be enough? – zcui93 Mar 10 '16 at 16:56
  • I think is `self.textView.font?.ascender` – TomCobo Mar 10 '16 at 17:16

3 Answers3

4

There is a diagram from the Apple document

Figure 9-4  Font metrics

From my understanding, font.descender + font.leading gives the distance between the first baseline and starting of the second line.

I would imagine font.lineHeight would give you the right number, if UITextField doesn't have a secret padding.


EDIT

UITextField and UITextView shared same UIFont property.

For UITextView, there's an extra textContainerInset can be set.

EDIT 2

A further look at the UITextView gives more clue about what can be achieved:

It actually has a textContainer property, which is a NSTextContainer.

The NSTextContainer class defines a region in which text is laid out. An NSLayoutManager object uses one or more NSTextContainer objects to determine where to break lines, lay out portions of text, and so on.

And it's been used by layoutManager, theoretically the padding to the top of first line of text could be found by usedRectForTextContainer(_:).

I will need to test this once I have a Mac in hand. :)

zcui93
  • 1,424
  • 16
  • 27
  • You are writing about `UITextField` and I'm asking about `UITextView`. Would it still work? And the problem is that the diagram explains UIFont only. UITextView adds its own top padding. – Rafa de King Mar 10 '16 at 17:08
  • Sorry about this, they both share the same `font : UIFont` property, so I believe if one works, the other should work. – zcui93 Mar 10 '16 at 17:11
3

Based on the documentation zcui93 gives, font.ascender will give you the offset to the baseline within the font. To get the baseline of the font within the UITextView you need to add in textContainerInset.top:

extension UITextView {
    func firstBaseline() -> CGFloat {
        let font = self.font ?? UIFont.systemFontOfSize(UIFont.systemFontSize())
        return font.ascender + textContainerInset.top
    }
}

There's a little bit of assumption here in defaulting to the system font if no font is set, but I'm not sure what a better guess would be.

Running the following in the playground will demonstrate the effect:

class Container : UITextView {
    override func drawRect(rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()
        CGContextSaveGState(context)

        let containerRect = UIEdgeInsetsInsetRect(bounds, textContainerInset)
        UIColor(red: 1, green: 0, blue: 0, alpha: 0.25).setFill()
        CGContextFillRect(context, containerRect)

        let baseline = firstBaseline()

        UIColor(red: 1, green: 0, blue: 0, alpha: 0.75).setStroke()
        CGContextSetLineWidth(context, 1)
        CGContextMoveToPoint(context, containerRect.origin.x, baseline)
        CGContextAddLineToPoint(context, containerRect.origin.x + containerRect.width, baseline)
        CGContextStrokePath(context)

        super.drawRect(rect)
    }
}

let textView = Container(frame: CGRect(x: 0, y: 0, width: 100, height: 30))
textView.font = UIFont.systemFontOfSize(UIFont.systemFontSize())
textView.text = "My Text"

And the result:

enter image description here

David Berry
  • 39,492
  • 12
  • 80
  • 91
0

In my case I was extending UITextField class and I just wanted to draw a line in the textfield baseline and I succeed with the following chunk:

self.svwLine = UIView(frame: CGRectMake(0,self.frame.size.height+(self.font?.descender)!,self.frame.size.width,2))
self.svwLine.backgroundColor = UIColor.whiteColor()
self.addSubview(self.svwLine)