Using a CALayer to highlight text in a UITextView which spans multiple lines

前端 未结 1 676
谎友^
谎友^ 2020-12-24 04:05

This is a continuation of Getting CGRect for text in a UITextView for the purpose of highlighting with a CALayer. I\'m having trouble with getting the correct rectangle for

相关标签:
1条回答
  • 2020-12-24 04:36

    I've found the solution:

    Instead of using enumerateEnclosingRectsForGlyphRange: I use the NSString method enumerateSubstringsInRange:options:usingBlock:

    I enumerate the line fragments as usual, but instead of trying to use the enclosing rect enumeration method, I enumerate each character on the line while building the rect for the layer.

    -(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, CGRect usedRect, NSTextContainer *textContainer, NSRange lineRange, 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
     }];
    

    }

    I'm still working on multiple matches, i'll update the code once I get that working.

    0 讨论(0)
提交回复
热议问题