我正在尝试设置背景颜色/突出显示在UILabel内的文本.问题在于,还会突出显示添加到UILabel中以保持文本居中的换行符和空格.
注意UILabel最后一行之前的间距突出显示.此外,任何新行的开始和结束也突出显示.
我使用以下代码创建上面的示例:
-(void)createSomeLabel { // Create and position my label UILabel *someLabel = [[UILabel alloc] initWithFrame:CGRectMake(0,self.view.frame.size.width - 40,self.view.frame.size.height - 300)]; someLabel.center = CGPointMake(self.view.frame.size.width / 2,self.view.frame.size.height / 2); someLabel.textAlignment = NSTextAlignmentCenter; someLabel.textColor = [UIColor whiteColor]; someLabel.lineBreakMode = NSLineBreakByWordWrapping; someLabel.numberOfLines = 0; [self.view addSubview:someLabel]; // This string will be different lengths all the time NSString *someLongString = @"Here is a really long amount of text that is going to wordwrap/line break and I don't want to highlight the spacing. I want to just highlight the words and a single space before/after the word"; // Create attributed string NSMutableAttributedString *someLongStringAttr=[[NSMutableAttributedString alloc] initWithString:someLongString attributes:nil]; // Apply background color [someLongStringAttr addAttribute:NSBackgroundColorAttributeName value:[UIColor colorWithWhite:0 alpha:0.25] range:NSMakeRange(0,someLongStringAttr.length)]; // Set text of label someLabel.attributedText = someLongStringAttr; }
我想实现的输出是只突出显示文本和单词之间的空格,如果只有一个空格.文本的长度和UILabel的大小会不断变化,所以硬编码解决方案不是一个选择.
解决方法
在我看来,换行是问题.
我的想法是尝试知道UILabel何时会添加换行符,然后从被突出显示的字符范围中删除该字符.
我的想法是尝试知道UILabel何时会添加换行符,然后从被突出显示的字符范围中删除该字符.
看来,你不能只是问UILabel断线的地方,但是你可以检查一个NSString的大小,当你添加到一个标签.
使用这些信息,您可以逐个增加每个角色,不断检查高度,当高度变化时,您就知道有新行.
我举了一个例子,把Label的字符串和它分隔成UILabel中出现的各个行.一旦我有了每一行,我只是在每一行而不是整个字符串设置背景颜色.这样就可以消除背景颜色,也可以在换行符上设置背景颜色.
可能有更好的解决方案,这可能是为了更好的性能而被优化,但它是一个起点,它似乎起作用.
- (void)createSomeLabel { // Create and position my label UILabel *someLabel = [[UILabel alloc] initWithFrame:CGRectMake(0,self.view.frame.size.height / 2); someLabel.textAlignment = NSTextAlignmentCenter; someLabel.textColor = [UIColor whiteColor]; someLabel.lineBreakMode = NSLineBreakByWordWrapping; someLabel.numberOfLines = 0; [self.view addSubview:someLabel]; // This string will be different lengths all the time NSString *someLongString = @"Here is a really long amount of text that is going to wordwrap/line break and I don't want to highlight the spacing. I want to just highlight the words and a single space before/after the word"; // Create attributed string NSMutableAttributedString *someLongStringAttr=[[NSMutableAttributedString alloc] initWithString:someLongString attributes:nil]; // The idea here is to figure out where the UILabel would automatically make a line break and get each line of text separately. // Temporarily set the label to be that string so that we can guess where the UILabel naturally puts its line breaks. [someLabel setText:someLongString]; // Get an array of each individual line as the UILabel would present it. NSArray *allLines = getLinesForLabel(someLabel); [someLabel setText:@""]; // Loop through each line of text and apply the background color to just the text within that range. // This way,no whitespace / line breaks will be highlighted. __block int startRange = 0; [allLines enumerateObjectsUsingBlock:^(NSString *line,NSUInteger idx,BOOL *stop) { // The end range should be the length of the line,minus one for the whitespace. // If we are on the final line,there are no more line breaks so we use the whole line length. NSUInteger endRange = (idx+1 == allLines.count) ? line.length : line.length-1; // Apply background color [someLongStringAttr addAttribute:NSBackgroundColorAttributeName value:[UIColor colorWithWhite:0 alpha:0.25] range:NSMakeRange(startRange,endRange)]; // Update the start range to the next line startRange += line.length; }]; // Set text of label someLabel.attributedText = someLongStringAttr; } #pragma mark - Utility Functions static NSArray *getLinesForLabel(UILabel *label) { // Get the text from the label NSString *labelText = label.text; // Create an array to hold the lines of text NSMutableArray *allLines = [NSMutableArray array]; while (YES) { // Get the length of the current line of text int length = getLengthOfTextInFrame(label,labelText) + 1; // Add this line of text to the array [allLines addObject:[labelText substringToIndex:length]]; // Adjust the label text labelText = [labelText substringFromIndex:length]; // Check for the final line if(labelText.length<length) { [allLines addObject:labelText]; break; } } return [NSArray arrayWithArray:allLines]; } static int getLengthOfTextInFrame(UILabel *label,NSString *text) { // Create a block for getting the bounds of the current peice of text. CGRect (^boundingRectForLength)(int) = ^CGRect(int length) { NSString *cutText = [text substringToIndex:length]; CGRect textRect = [cutText boundingRectWithSize:CGSizeMake(label.frame.size.width,CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : label.font} context:nil]; return textRect; }; // Get the frame of the string for one character int length = 1; int lastSpace = 1; CGRect textRect = boundingRectForLength(length); CGFloat oneLineHeight = CGRectGetHeight(textRect); // Keep adding one character to the string until the height changes,then you know you have a new line while (textRect.size.height <= oneLineHeight) { // If the next character is white space,save the current length. // It could be the end of the line. // This will not work for character wrap. if ([[text substringWithRange:NSMakeRange (length,1)] isEqualToString:@" "]) { lastSpace = length; } // Increment length and get the new bounds textRect = boundingRectForLength(++length); } return lastSpace; }