UILabel Detection Line Break

I am currently using UILabel to display multiple lines of text. The greatest line deviation is set to NSLineBreakByWordWrapping , so the label automatically inserts line breaks. How can I determine where these line breaks are? Basically, I want to return a line with each track included \n .

+8
uilabel nsstring line-breaks
source share
2 answers

Here is my job for detecting line breaks inside UILabel

 - (int)getLengthForString:(NSString *)str fromFrame:(CGRect)frame withFont:(UIFont *)font { int length = 1; int lastSpace = 1; NSString *cutText = [str substringToIndex:length]; CGSize textSize = [cutText sizeWithFont:font constrainedToSize:CGSizeMake(frame.size.width, frame.size.height + 500)]; while (textSize.height <= frame.size.height) { NSRange range = NSMakeRange (length, 1); if ([[str substringWithRange:range] isEqualToString:@" "]) { lastSpace = length; } length++; cutText = [str substringToIndex:length]; textSize = [cutText sizeWithFont:font constrainedToSize:CGSizeMake(frame.size.width, frame.size.height + 500)]; } return lastSpace; } -(NSString*) getLinebreaksWithString:(NSString*)labelText forWidth:(CGFloat)lblWidth forPoint:(CGPoint)point { //Create Label UILabel *label = [[UILabel alloc] init]; label.text = labelText; label.numberOfLines = 0; label.lineBreakMode = NSLineBreakByWordWrapping; //Set frame according to string CGSize size = [label.text sizeWithFont:label.font constrainedToSize:CGSizeMake(lblWidth, MAXFLOAT) lineBreakMode:UILineBreakModeWordWrap]; [label setFrame:CGRectMake(point.x , point.y , size.width , size.height)]; //Add Label in current view [self.view addSubview:label]; //Count the total number of lines for the Label which has NSLineBreakByWordWrapping line break mode int numLines = (int)(label.frame.size.height/label.font.leading); //Getting and dumping lines from text set on the Label NSMutableArray *allLines = [[NSMutableArray alloc] init]; BOOL shouldLoop = YES; while (shouldLoop) { //Getting length of the string from rect with font int length = [self getLengthForString:labelText fromFrame:CGRectMake(point.x, point.y, size.width, size.height/numLines) withFont:label.font] + 1; [allLines addObject:[labelText substringToIndex:length]]; labelText = [labelText substringFromIndex:length]; if(labelText.length<length) shouldLoop = NO; } [allLines addObject:labelText]; //NSLog(@"\n\n%@\n",allLines); return [allLines componentsJoinedByString:@"\n"]; } 

How to use

 NSString *labelText = @"We are what our thoughts have made us; so take care about what you think. Words are secondary. Thoughts live; they travel far."; NSString *stringWithLineBreakChar = [self getLinebreaksWithString:labelText forWidth:200 forPoint:CGPointMake(15, 15)]; NSLog(@"\n\n%@",stringWithLineBreakChar); 

You just need to set the parameters needed by getLinebreaksWithString , and you will get a string with the word "\ n" included.

audio output Result of NSLog and Simulator

+3
source share

Here is my solution to this problem.
I iterate over all the whitespace in the provided string, set the substrings (from the beginning to the current space) to the label, and check the difference in height. When the height changes, I insert a new line character (simulates a line break).

 func wordWrapFormattedStringFor(string: String) -> String { // Save label state let labelHidden = label.isHidden let labelText = label.text // Set text to current label and size it to fit the content label.isHidden = true label.text = string label.sizeToFit() label.layoutIfNeeded() // Prepare array with indexes of all whitespace characters let whitespaceIndexes: [String.Index] = { let whitespacesSet = CharacterSet.whitespacesAndNewlines var indexes: [String.Index] = [] string.unicodeScalars.enumerated().forEach { i, unicodeScalar in if whitespacesSet.contains(unicodeScalar) { let index = string.index(string.startIndex, offsetBy: i) indexes.append(index) } } // We want also the index after the last character so that when we make substrings later we include also the last word // This index can only be used for substring to this index (not from or including, since it points to \0) let index = string.index(string.startIndex, offsetBy: string.characters.count) indexes.append(index) return indexes }() var reformattedString = "" let boundingSize = CGSize(width: label.bounds.width, height: CGFloat.greatestFiniteMagnitude) let attributes = [NSFontAttributeName: font] var runningHeight: CGFloat? var previousIndex: String.Index? whitespaceIndexes.forEach { index in let string = string.substring(to: index) let stringHeight = string.boundingRect(with: boundingSize, options: .usesLineFragmentOrigin, attributes: attributes, context: nil).height var newString: String = { if let previousIndex = previousIndex { return string.substring(from: previousIndex) } else { return string } }() if runningHeight == nil { runningHeight = stringHeight } if runningHeight! < stringHeight { // Check that we can create a new index with offset of 1 and that newString does not contain only a whitespace (for example if there are multiple consecutive whitespaces) if newString.characters.count > 1 { let splitIndex = newString.index(newString.startIndex, offsetBy: 1) // Insert a new line between the whitespace and rest of the string newString.insert("\n", at: splitIndex) } } reformattedString += newString runningHeight = stringHeight previousIndex = index } // Restore label label.text = labelText label.isHidden = labelHidden return reformattedString } 

Image - Comparison of the output string with the text labels.

This solution worked very well in my case, hope this helps.

0
source share

All Articles