CGRect为多行文本选定的UITextRange调整?

我已经使用这个答案为了创build一个特定范围的文本CGRect。

在这个UITextView我已经设置了attributedText (所以我得到了一堆带有不同字形大小的样式文本)。

这对左alignment的第一行文本非常有用,但是在使用NSTextAlignmentJustifiedNSTextAlignmentCenter时,它会有一些非常奇怪的结果。

当换行或(有时)如果有换行符时,它也不能正确计算。

我得到这样的东西(这是中心alignment):

在这里输入图像说明

相反,我期望这一点:

在这里输入图像说明

这个有一个\n分行符 – 前两个代码位被突出显示,但最后一个more code for you to see不是因为文本包装没有考虑到x,y的计算。

这是我的实现:

 - (void)formatMarkdownCodeBlockWithAttributes:(NSDictionary *)attributesDict withHighlightProperties:(NSDictionary *)highlightProperties forFontSize:(CGFloat)pointSize { NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"`.+?`" options:NO error:nil]; NSArray *matchesArray = [regex matchesInString:[self.attributedString string] options:NO range:NSMakeRange(0, self.attributedString.length)]; for (NSTextCheckingResult *match in matchesArray) { NSRange range = [match range]; if (range.location != NSNotFound) { self.textView.attributedText = self.attributedString; CGRect codeRect = [self frameOfTextRange:range forString:[[self.attributedString string] substringWithRange:range] forFontSize:pointSize]; UIView *highlightView = [[UIView alloc] initWithFrame:codeRect]; highlightView.layer.cornerRadius = 4; highlightView.layer.borderWidth = 1; highlightView.backgroundColor = [highlightProperties valueForKey:@"backgroundColor"]; highlightView.layer.borderColor = [[highlightProperties valueForKey:@"borderColor"] CGColor]; [self.contentView insertSubview:highlightView atIndex:0]; [self.attributedString addAttributes:attributesDict range:range]; //strip first and last ` [[self.attributedString mutableString] replaceOccurrencesOfString:@"(^`|`$)" withString:@" " options:NSRegularExpressionSearch range:range]; } } } - (CGRect)frameOfTextRange:(NSRange)range forString:(NSString *)string forFontSize:(CGFloat)pointSize { self.textView.selectedRange = range; UITextRange *textRange = [self.textView selectedTextRange]; CGRect rect = [self.textView firstRectForRange:textRange]; //These three lines are a workaround for getting the correct width of the string since I'm always using the monospaced Menlo font. rect.size.width = ((pointSize / 1.65) * string.length) - 4; rect.origin.x+=2; rect.origin.y+=2; return rect; } 

哦,如果你想要它,这里是我玩的string:

 *This* is **awesome** @mention `code` more \n `code and code` #hashtag [markdown](http://google.com) __and__ @mention2 {#FFFFFF|colored text} This**will also** work but ** will not ** **work** Also, some `more code for you to see` 

注意:请不要build议我使用TTTAttributedLabelOHAttributedLabel

我想你所有的问题都是因为指令的顺序不正确。

你必须

  1. 设置文本alignment
  2. 查找所需的子string并向其添加特定的属性
  3. 只有使用子视图突出显示string。

在这种情况下,您也不需要使用“解决方法来获取正确的string宽度,因为我总是使用等宽字体”。

我简化了你的代码,使其更容易理解。

结果: 在这里输入图像说明

 - (void)viewDidLoad { [super viewDidLoad]; NSDictionary *basicAttributes = @{ NSFontAttributeName : [UIFont boldSystemFontOfSize:18], NSForegroundColorAttributeName : [UIColor blackColor] }; NSDictionary *attributes = @{ NSFontAttributeName : [UIFont systemFontOfSize:15], NSForegroundColorAttributeName : [UIColor darkGrayColor]}; _textView.attributedText = [[NSAttributedString alloc] initWithString: @"*This* is **awesome** @mention `code` more \n `code and code` #hashtag [markdown](http://google.com) __and__ @mention2 {#FFFFFF|colored text} This**will also** work but ** will not ** **work** Also, some `more code for you to see`" attributes:attributes]; _textView.textAlignment = NSTextAlignmentCenter; [self formatMarkdownCodeBlockWithAttributes:basicAttributes]; } - (void)formatMarkdownCodeBlockWithAttributes:(NSDictionary *)attributesDict { NSMutableString *theString = [_textView.attributedText.string mutableCopy]; NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"`.+?`" options:NO error:nil]; NSArray *matchesArray = [regex matchesInString:theString options:NO range:NSMakeRange(0, theString.length)]; NSMutableAttributedString *theAttributedString = [_textView.attributedText mutableCopy]; for (NSTextCheckingResult *match in matchesArray) { NSRange range = [match range]; if (range.location != NSNotFound) { [theAttributedString addAttributes:attributesDict range:range]; } } _textView.attributedText = theAttributedString; for (NSTextCheckingResult *match in matchesArray) { NSRange range = [match range]; if (range.location != NSNotFound) { CGRect codeRect = [self frameOfTextRange:range]; UIView *highlightView = [[UIView alloc] initWithFrame:codeRect]; highlightView.layer.cornerRadius = 4; highlightView.layer.borderWidth = 1; highlightView.backgroundColor = [UIColor yellowColor]; highlightView.layer.borderColor = [[UIColor redColor] CGColor]; [_textView insertSubview:highlightView atIndex:0]; } } } - (CGRect)frameOfTextRange:(NSRange)range { self.textView.selectedRange = range; UITextRange *textRange = [self.textView selectedTextRange]; CGRect rect = [self.textView firstRectForRange:textRange]; return rect; } 

我只是不得不做类似的事情。 假设你正在使用iOS 7:

 // Build the range that you want for your text NSRange range = NSMakeRange(location, length); // Get the substring of the attributed text at that range NSAttributedString *substring = [textView.attributedText attributedSubstringFromRange:range]; // Find the frame that would enclose the substring of text. CGRect frame = [substring boundingRectWithSize:maxSize options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) context:nil]; 

这应该使用分配给属性string的NSTextAlignment。

正如@Avt回答https://stackoverflow.com/a/22572201/3549781这个问题。 我只是回答换行问题。 即使您使用iOS 7 +,也会出现这种换行问题

 [self.textView selectedTextRange] or [self.textView positionFromPosition: offset:] 

我们只需要在调用firstRectForRange之前确保textView的布局

 [self.textView.layoutManager ensureLayoutForTextContainer:self.textView.textContainer]; 

礼貌: https : //stackoverflow.com/a/25983067/3549781

PS:起初我把这个添加为对这个问题的评论。 由于大多数人不读评论我加了这个答案。