Używanie Calayera do podświetlania tekstu w widoku UITextView, który obejmuje wiele linii
Jest to kontynuacja uzyskiwania CGRect dla tekstu w widoku UITextView w celu podświetlenia za pomocą CALayer. Mam problem z uzyskaniem poprawnego prostokąta dla zakresów w każdym fragmencie linii.
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;
}
}];
}];
To moja obecna próba. W zasadzie używam enumerateLineFragmentsForGlyphRange: usingBlock: do przechodzenia przez każdą linię. Następnie używam enumerateEnclosingRectsForGlyphRange: withinSelectedGlyphRange: usingBlock: aby upewnić się, że zakres tekstu na bieżąca linia odpowiada zakresowi linii i ma tę samą współrzędną Y. Czasami to działa, a czasami nie.
Wygląda na to, że jeśli szukany tekst znajduje się w pobliżu zwracanego tekstu, odciąga on podświetlenie. (współrzędna y).
Na tym zrzucie ekranu" zwraca zakres znaków, które zostały wygenerowane " ma być podświetlone.
Wygląda na to, że jeśli tekst nie znajduje się w pobliżu zwracanej lub białej spacji, działa to poprawnie:
Am I missing coś?
UPDATE:
Trochę zawęziłem problem, uważam, że enumerateLineFragmentsForGlyphRange: usingBlock: pomija linie, które mają zwroty.
1 answers
Znalazłem rozwiązanie:
Zamiast używać enumerateEnclosingRectsForGlyphRange: używam metody NSString enumerateSubstringsInRange: options: usingBlock:
Wyliczam fragmenty linii jak zwykle, ale zamiast używać metody enumeracji rect, wyliczam każdy znak w linii podczas budowania rect dla warstwy.
-(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
}];
}
Nadal pracuję nad wieloma dopasowaniami, zaktualizuję kod, gdy to zadziała.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-29 06:36:53