这是
Getting CGRect for text in a UITextView for the purpose of highlighting with a CALayer的延续.我在为每个线段中的范围获取正确的矩形时遇到问题.
NSString* searchString = @"Returns the range of characters that generated"; NSRange match = [[[self textView]text]rangeOfString:searchString]; NSRange matchingGlyphRange = [manager glyphRangeForCharacterRange:match actualCharacterRange:NULL]; [manager enumerateLineFragmentsForGlyphRange:matchingGlyphRange usingBlock: ^(CGRect lineRect,CGRect usedRect,NSTextContainer *textContainer,NSRange lineRange,BOOL *stop) { NSRange currentRange = NSIntersectionRange(lineRange,matchingGlyphRange); [manager enumerateEnclosingRectsForGlyphRange:currentRange withinSelectedGlyphRange:NSMakeRange(NSNotFound,0) inTextContainer:textContainer usingBlock: ^(CGRect rect,BOOL* stop) { if (usedRect.origin.y == rect.origin.y && NSLocationInRange(currentRange.location,lineRange)) { CGRect theRect = [manager boundingRectForGlyphRange:currentRange inTextContainer:textContainer]; CALayer* roundRect = [CALayer layer]; [roundRect setFrame:theRect]; [roundRect setBounds:theRect]; [roundRect setCornerRadius:5.0f]; [roundRect setBackgroundColor:[[UIColor blueColor]CGColor]]; [roundRect setOpacity:0.2f]; [roundRect setBorderColor:[[UIColor blackColor]CGColor]]; [roundRect setBorderWidth:3.0f]; [roundRect setShadowColor:[[UIColor blackColor]CGColor]]; [roundRect setShadowOffset:CGSizeMake(20.0f,20.0f)]; [roundRect setShadowOpacity:1.0f]; [roundRect setShadowRadius:10.0f]; [[[self textView]layer]addSublayer:roundRect]; *stop = YES; } }]; }];
这是我目前的尝试.我基本上使用enumerateLineFragmentsForGlyphRange:usingBlock:循环遍历每一行.然后我使用enumerateEnclosingRectsForGlyphRange:withinSelectedGlyphRange:usingBlock:以确保当前行上的文本范围与行的范围匹配并具有相同的Y坐标.有时候这种方法有效,有时则不然.
似乎如果搜索文本靠近返回,它会突出显示突出显示. (y坐标).
似乎文本不在返回或空格附近,这可以正常工作:
我错过了什么吗?
更新:
我已经把问题缩小了一点,我相信enumerateLineFragmentsForGlyphRange:usingBlock:正在跳过返回的行.
解决方法
我找到了解决方案:
而不是使用enumerateEnclosingRectsForGlyphRange:我使用NSString方法enumerateSubstringsInRange:options:usingBlock:
我像往常一样枚举行片段,但是我没有尝试使用封闭的rect枚举方法,而是在构建图层的rect时枚举行上的每个字符.
-(void)drawLayerForTextHighlightWithString:(NSString*)string { for (CALayer* eachLayer in [self highlightLayers]) { [eachLayer removeFromSuperlayer]; } NSLayoutManager* manager = [[self textView]layoutManager]; // Find the string NSRange match = [[[self textView]text]rangeOfString:string options: NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch]; // Convert it to a glyph range NSRange matchingGlyphRange = [manager glyphRangeForCharacterRange:match actualCharacterRange:NULL]; // Enumerate each line in that glyph range (this will fire for each line that the match spans) [manager enumerateLineFragmentsForGlyphRange:matchingGlyphRange usingBlock: ^(CGRect lineRect,BOOL *stop) { // currentRange uses NSIntersectionRange to return the range of the text that is on the current line NSRange currentRange = NSIntersectionRange(lineRange,matchingGlyphRange); // This rect will be built by enumerating each character in the line,and adding to it's width __block CGRect finalLineRect = CGRectZero; // Here we use enumerateSubstringsInRange:... to go through each glyph and build the final rect for the line [[[self textView]text]enumerateSubstringsInRange:currentRange options:NSStringEnumerationByComposedCharacterSequences usingBlock: ^(NSString* substring,NSRange substringRange,NSRange enclostingRange,BOOL* stop) { // The range of the single glyph being enumerated NSRange singleGlyphRange = [manager glyphRangeForCharacterRange:substringRange actualCharacterRange:NULL]; // get the rect for that glyph CGRect glyphRect = [manager boundingRectForGlyphRange:singleGlyphRange inTextContainer:textContainer]; // check to see if this is the first iteration,if not add the width to the final rect for the line if (CGRectEqualToRect(finalLineRect,CGRectZero)) { finalLineRect = glyphRect; } else { finalLineRect.size.width += glyphRect.size.width; } }]; // once we get the rect for the line,draw the layer UIEdgeInsets textContainerInset = [[self textView]textContainerInset]; finalLineRect.origin.x += textContainerInset.left; finalLineRect.origin.y += textContainerInset.top; CALayer* roundRect = [CALayer layer]; [roundRect setFrame:finalLineRect]; [roundRect setBounds:finalLineRect]; [roundRect setCornerRadius:5.0f]; [roundRect setBackgroundColor:[[UIColor blueColor]CGColor]]; [roundRect setOpacity:0.2f]; [roundRect setBorderColor:[[UIColor blackColor]CGColor]]; [roundRect setBorderWidth:3.0f]; [roundRect setShadowColor:[[UIColor blackColor]CGColor]]; [roundRect setShadowOffset:CGSizeMake(20.0f,20.0f)]; [roundRect setShadowOpacity:1.0f]; [roundRect setShadowRadius:10.0f]; [[[self textView]layer]addSublayer:roundRect]; [[self highlightLayers]addObject:roundRect]; // continues for each line }];
}
我还在进行多项比赛,一旦我开始工作,我就会更新代码.