I wanted to know when a text is wrapped by the frame of the text view is there any delimiter with which we can identify whether the text is wrapped or not.
For insta
I found the perfect solution to this problem in Apple's Text Layout Programming Guide. Here is the solution Apple provides:
NSLayoutManager *layoutManager = [textView layoutManager];
unsigned numberOfLines, index;
unsigned numberOfGlyphs = [layoutManager numberOfGlyphs];
NSRange lineRange;
for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){
(void) [layoutManager lineFragmentRectForGlyphAtIndex:index effectiveRange:&lineRange];
index = NSMaxRange(lineRange);
}
This could easily be written into an extension for UITextView, or as a standalone method taking in a UITextView object as a parameter
Improved and update Luke Chase's answer to Swift 5, XCode 11, iOS 13 to get text view number of lines and autoresize table view cell height.
You can use storyboard with static cell height to design it as you want. Make UITextView scroll enable: false (disable scroll).
In viewDidLoad add your estimated row height and your textView delegate.
override func viewDidLoad() {
super.viewDidLoad()
quoteTextView.delegate = self
tableView.estimatedRowHeight = 142
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
extension ViewController: UITextViewDelegate {
func textViewDidChange(_ textView: UITextView) {
// Refresh tableView cell
if textView.numberOfLines > 2 { // textView in storyboard has two lines, so we match the design
// Animated height update
DispatchQueue.main.async {
self.tableView?.beginUpdates()
self.tableView?.endUpdates()
}
}
}
}
extension UITextView {
var numberOfLines: Int {
// Get number of lines
let numberOfGlyphs = self.layoutManager.numberOfGlyphs
var index = 0, numberOfLines = 0
var lineRange = NSRange(location: NSNotFound, length: 0)
while index < numberOfGlyphs {
self.layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
index = NSMaxRange(lineRange)
numberOfLines += 1
}
return numberOfLines
}
}
-> Do not forgot to disable uitextview scroll. Cheers!<-
Preview
This variation takes into account how you wrap your lines and the max size of the UITextView
, and may output a more precise height. For example, if the text doesn't fit it will truncate to the visible size, and if you wrap whole words (which is the default) it may result in more lines than if you do otherwise.
UIFont *font = [UIFont boldSystemFontOfSize:11.0];
CGSize size = [string sizeWithFont:font
constrainedToSize:myUITextView.frame.size
lineBreakMode:UILineBreakModeWordWrap]; // default mode
float numberOfLines = size.height / font.lineHeight;
You need to use the lineHeight
property, and font lineHeight
:
Objective-C
int numLines = txtview.contentSize.height / txtview.font.lineHeight;
Swift
let numLines = (txtview.contentSize.height / txtview.font.lineHeight) as? Int
I am getting correct number of lines, hope it help you also.
func numberOfLines(textView: UITextView) -> Int {
let layoutManager = textView.layoutManager
let numberOfGlyphs = layoutManager.numberOfGlyphs
var lineRange: NSRange = NSMakeRange(0, 1)
var index = 0
var numberOfLines = 0
while index < numberOfGlyphs {
layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
index = NSMaxRange(lineRange)
numberOfLines += 1
}
return numberOfLines
}
Working Fine for me
Swift 5.0
extension UITextView {
func sizeFit(width: CGFloat) -> CGSize {
let fixedWidth = width
let newSize = sizeThatFits(CGSize(width: fixedWidth, height: .greatestFiniteMagnitude))
return CGSize(width: fixedWidth, height: newSize.height)
}
func numberOfLine() -> Int {
let size = self.sizeFit(width: self.bounds.width)
let numLines = Int(size.height / (self.font?.lineHeight ?? 1.0))
return numLines
}
}