Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSBackgroundColorAttributeName in textView doesn't respect range if highlighted word is first of a line

I'm implementing a "search in chat" feature and I want the searched word to be highlighted in messages. The problem, as described in title, is that if the word is the first of a line (long messages are clearly multi-line), the entire line is highlighted instead of the single word.

While debugging, I also tried to apply an underline instead of backgroundcolor, and the underline is correct. I can't figure out where's the problem. My app's chat is based on JSQMessagesViewController so I was thinking that the problem could be there.

[attributedString addAttribute:NSBackgroundColorAttributeName
                         value:backColor
                         range:wordRange];
[attributedString addAttribute:NSUnderlineStyleAttributeName
                         value:@(NSUnderlineStyleSingle)
                         range:wordRange];

cell.textView.attributedText = attributedString;

I don't post the code that calculates range because range is correct; in fact, if I look at attributedString's preview in debug (where I assign it to cell.textView.attributedText) I can see that only the word is highlighted, and not all the string.

Here's an example:
Example

like image 453
Christian Casalini Avatar asked Sep 06 '19 10:09

Christian Casalini


2 Answers

Seems like a bug in the system framework, so probably best bet would be to add one more line of code, setting background color back to "unchanged", directly after the last character where background should be changed. Good luck!

like image 62
Adam Tucholski Avatar answered Nov 15 '22 20:11

Adam Tucholski


After taking a look at official documentation, I found that there are three methods which do similar action.

  1. setAttributes:range:
  2. addAttribute:value:range:
  3. addAttributes:range:

So, possibly, other method, for example setAttributes:range:, may fix you problem.

[attributedString setAttributes:@{NSBackgroundColorAttributeName : backColor}
                          range:wordRange];

cell.textView.attributedText = attributedString;

Furthermore, there is a similar question on stackoverflow. Maybe this answer will help you.

NSDictionary *stringAttributes = [NSDictionary dictionaryWithObject:(id)backColor.CGColor
                                                             forKey:(id)kCTBackgroundColorAttributeName];
[attributedString addAttributes:stringAttributes 
                          range:wordRange];

cell.textView.attributedText = attributedString;

Update #1

Just found Attributed String Programming Guide.
It says,

All of the methods for changing a mutable attributed string properly update the mapping between characters and attributes, but after a change some inconsistencies can develop.

Perhaps, the above reason causes your problem... I'm not sure can it help or no, but there is example:

NSMutableAttributedString *string; // assume string exists
NSRange selectedRange; // assume this is set

NSURL *linkURL = [NSURL URLWithString:@"http://www.apple.com/"];

[string beginEditing]; // ★★★ Apple uses beginEditing ★★★
[string addAttribute:NSLinkAttributeName
               value:linkURL
               range:selectedRange]; 
[string addAttribute:NSForegroundColorAttributeName
               value:[NSColor blueColor]
               range:selectedRange];
[string addAttribute:NSUnderlineStyleAttributeName
               value:[NSNumber numberWithInt:NSSingleUnderlineStyle]
               range:selectedRange];
[string endEditing]; // ★★★ and endEditing ★★★
like image 23
Yeheshuah Avatar answered Nov 15 '22 21:11

Yeheshuah