Hassan Taleb
Hassan Taleb

Reputation: 2526

Get the NSRange of last line inside one line

How can I get the NSRange of last line inside one line? (If cursor is at the end of it)

enter image description here

In the image example, I want to get the line range of the text in red box. My code now get the range of whole line (green box):

var currentLineRange: NSRange {
    let nsText = self.text as NSString
    let currentLineRange = nsText.lineRange(for: self.selectedRange)
    return currentLineRange
}

Upvotes: 0

Views: 466

Answers (1)

Sweeper
Sweeper

Reputation: 270995

Notice that the range you want is a function of the width with which you have laid out the text, and the font of the text, among many other things. You cannot tell this from a String alone, as a String is just some Characters, and does not have those information. The lineRange method looks for new line characters in the string, which there evidently aren't, in your Lorem Ipsum paragraph, between "of" and "Lorem", hence that is not counted as a "line".

Assuming this is displayed in a UITextView (as that is what you have tagged the question with), you can use its layoutManager to get the range you want.

let selectedRange = textview.selectedRange
let glyphRange = textview.layoutManager.glyphRange(forCharacterRange: selectedRange, actualCharacterRange: nil)

// if the selection starts after the last glyph, glyphRange.lowerBound is not a valid glyph index
// so we need to use the last glyph in that case
let glyphIndex = glyphRange.lowerBound == textview.layoutManager.numberOfGlyphs ?
                glyphRange.lowerBound - 1 : glyphRange.lowerBound

var effectiveGlyphRange = NSRange(location: 0, length: 0)

// this gets the *glyph* range of the line
textview.layoutManager.lineFragmentRect(forGlyphAt: glyphIndex, effectiveRange: &effectiveGlyphRange)
let effectiveCharRange = textview.layoutManager.characterRange(forGlyphRange: effectiveGlyphRange, actualGlyphRange: nil)

This code will get the range of the line (aka line fragment) containing the start of the selected range.

If you want to get a range of multiple lines when multiple lines are selected (similar to how lineRange would have behaved), it should be trivial to modify the code to also get the range of the line containing the end of the selected range, then combine the two ranges.

Upvotes: 2

Related Questions