Reputation: 711
I have a gridview
containing the TextView
. There is also a search bar. When I type anything to search the search text should be highlighted in the TextView
same as in Xcode
or browser.
How can I implement this functionality?
Upvotes: 3
Views: 4020
Reputation: 1423
@nsz's answer is correct. But it may not be efficient. Because you can't assume that how the user is going to search text. Example: if original text is "iPhone has released new 8s" and the search text is "iphone 8", in this case @nsz's answer won't work. To work with this kind of situation you have to split the keywords and find the word distance since '8' and '8s' is not same. To find word distance, you can use Levenshtein's algorithm.Below is the implementation:
-(float)LevenshteinAlgo:(NSString *)mainString withString:(NSString *)wordToCompare
{
[mainString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[wordToCompare stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
mainString = [mainString lowercaseString];
wordToCompare = [wordToCompare lowercaseString];
NSInteger k, i, j, cost, * d, distance;
NSInteger n = [mainString length];
NSInteger m = [wordToCompare length];
if( n++ != 0 && m++ != 0 ) {
d = malloc( sizeof(NSInteger) * m * n );
for( k = 0; k < n; k++)
d[k] = k;
for( k = 0; k < m; k++)
d[ k * n ] = k;
for( i = 1; i < n; i++ )
for( j = 1; j < m; j++ ) {
if( [mainString characterAtIndex: i-1] ==
[wordToCompare characterAtIndex: j-1] )
cost = 0;
else
cost = 1;
d[ j * n + i ] = [self CstyleMinimum: d [ (j - 1) * n + i ] + 1
andOf: d[ j * n + i - 1 ] + 1
andOf: d[ (j - 1) * n + i - 1 ] + cost ];
if( i>1 && j>1 && [mainString characterAtIndex: i-1] ==
[wordToCompare characterAtIndex: j-2] &&
[mainString characterAtIndex: i-2] ==
[wordToCompare characterAtIndex: j-1] )
{
d[ j * n + i] = [self CstyleMinimum: d[ j * n + i ]
andOf: d[ (j - 2) * n + i - 2 ] + cost ];
}
}
distance = d[ n * m - 1 ];
free( d );
return distance;
}
return 0.0;
}
-(NSInteger)CstyleMinimum:(NSInteger)a andOf:(NSInteger)b andOf:(NSInteger)c
{
NSInteger min = a;
if ( b < min )
min = b;
if( c < min )
min = c;
return min;
}
-(NSInteger)CstyleMinimum:(NSInteger)a andOf:(NSInteger)b
{
NSInteger min=a;
if (b < min)
min=b;
return min;
}
So the whole process will be like below :
-(NSString*)getSuggestedString:(NSString *)main key:(NSString *)keyword{
NSString *suggested = nil;
NSArray *split = [main componentsSeparatedByString:@" "];
for (NSString *str in split){
float distance = floorf([self LevenshteinAlgo:str withString:keyword]);
if(distance == 1 || distance == 2){
suggested = str;
}
}
return suggested;
}
-(void)setColorForText:(NSString*) textToFind withColor:(UIColor*) color
{
NSRange range = [self.mutableString rangeOfString:textToFind options:NSCaseInsensitiveSearch];
if (range.location == NSNotFound) {
//TODO: apply algo
NSString *suggested = [self getSuggestedString:self.mutableString key:textToFind];
NSRange srange = [self.mutableString rangeOfString:suggested!=nil?suggested:textToFind options:NSCaseInsensitiveSearch];
if(srange.location != NSNotFound){
[self addAttribute:NSForegroundColorAttributeName value:color range:srange];
}
}else{
[self addAttribute:NSForegroundColorAttributeName value:color range:range];
}
}
Use this full code in a NSMutableAttributedString
subclass. Paste the code below in your subclass.h
file.
@interface NSMutableAttributedString (Color){
}
-(void)setColorForText:(NSString*) textToFind withColor:(UIColor*) color;
@end
Finally use this like below :
NSMutableAttributedString *bold = [[NSMutableAttributedString alloc]initWithString:fulltext];
[bold setColorForText:key withColor:[UIColor redColor]];
I have been using this in my app for quite long time. You can try
Upvotes: 1
Reputation: 3252
I've tested the following code, which highlights the specific string in a UITextView:
-(void) highlightText:(NSString *)srcTxt {
int srcTxtLen = srcTxt.length;
int idx = 0;
while (idx<(self.txtView.text.length-srcTxtLen)) {
NSRange srcRange = NSMakeRange(idx, srcTxtLen);
if ([[self.txtView.text substringWithRange:srcRange] isEqualToString:srcTxt]) {
NSMutableAttributedString *tmpAttrTxt = [[NSMutableAttributedString alloc] initWithAttributedString:self.txtView.attributedText];
[tmpAttrTxt addAttribute:NSBackgroundColorAttributeName value:[UIColor yellowColor] range:srcRange];
self.txtView.attributedText = tmpAttrTxt;
idx += srcTxtLen;
} else {
idx++;
}
}
}
Hope it helps you. Of course it can be optimized and/or customized for your specific needs.
Upvotes: 9
Reputation: 3699
From what I understand from your question, you need the functionality to highlight the text (in the textview, which is in gridview) that matches the text you entered in the search bar. This being the case, you can try the following:
implement the method - (BOOL)searchBar:(UISearchBar *)searchBar shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
for your search bar.
Use attributed text for the text in the grid. (change to attributed text from plain text in xib)
Each time your program enters into the method above, extract the text variable, and accordingly update all your textViews with appropriate attributed strings. For this, you could use something like:
NSRange highLightAt = NSMakeRange(17,2); //based on the text in search bar
NSMutableAttributedString * string = [[NSMutableAttributedString alloc] initWithString:@"You searched for me !!!"];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:highLightAt];
self.textView.attributedText = string;
I hope you get the idea.
Upvotes: 0