Suggest # tags when typing (e.g. Twitter) for iPhone UITextView

I am creating an application that uses hashtags such as Twitter or Tweetbot. When you enter a message, if you enter a hashtag character, I would like to suggest tags that match the current type.

I already figured out how to make the UITableView appear and show a list of hashtags, but I can't figure out how to do this:

  • Get NSRange current input word,
  • See if this range is formatted as hashtag ( NSRegularExpression @"#\\w\\w*" )
  • (From now on, I have code to find the appropriate hashtags and show them in a UITableView)

Can someone help me with steps 1 and 2? I was thinking about using textViewDidChange: but I am worried that application performance could be affected if I constantly run methods every time the characters change.

Thanks!

+4
source share
2 answers

I get it! I ended up using the textViewDidChange: and textViewDidChangeSelection: methods.

To get the NSRange current hashtag that was typed, I ran a for loop on NSRegularExpression matches in the text string. From there, I used NSLocationInRange to find out if the current cursor position has crossed any of the hashtags.

Here is the code:

 //Get the ranges of current hashtags NSArray *hashtagRanges = [StringChecker rangesOfHashtagsInString:textView.text]; NSTextCheckingResult *currentHashtag; if ([hashtagRanges count] >0) { //List the ranges of all the hashtags for (int i = 0; i<[hashtagRanges count]; i++) { NSTextCheckingResult *hashtag = [hashtagRanges objectAtIndex:i]; //Check if the currentRange intersects the hashtag //Have to add an extra space to the range for if you're at the end of a hashtag. (since NSLocationInRange uses a < instead of <=) NSRange currentlyTypingHashtagRange = NSMakeRange(hashtag.range.location, hashtag.range.length + 1); if (NSLocationInRange(currentRange.location, currentlyTypingHashtagRange)) { //If the cursor is over the hashtag, then snag that hashtag for matching purposes. currentHashtag = hashtag; } } if (currentHashtag){ //If we found one hashtag that we're currently editing //Display the hashtag suggester, feed it the current hashtag for matching. [self showTagTable]; //Get the current list of hashtags into an array NSFetchRequest *hashtagRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *tagEntityDescription = [NSEntityDescription entityForName:@"Tags" inManagedObjectContext:self.note.managedObjectContext]; [hashtagRequest setEntity:tagEntityDescription]; NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"dateLastUsed" ascending:YES]; NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor]; [hashtagRequest setSortDescriptors:sortDescriptors]; NSPredicate *tagPredicate = [NSPredicate predicateWithFormat:@"name contains[c] %@", [noteTextView.text substringWithRange:currentHashtag.range]]; [hashtagRequest setPredicate:tagPredicate]; tagsToDisplay = (NSMutableArray *)[self.note.managedObjectContext executeFetchRequest:hashtagRequest error:nil]; [tagListTable reloadData]; //If there are no matching hashtags, then let hide the tag table. if ([tagsToDisplay count] == 0) { [self hideTagTable]; return; } } 

The StringChecker class is custom that I wrote, it just has class methods that parse strings. I made the StringChecker class because the methods are used in several places in the application. Here's the method:

  #pragma mark - Hashtag Methods +(NSArray *)rangesOfHashtagsInString:(NSString *)string { NSRegularExpression *hashtagDetector = [[NSRegularExpression alloc] initWithPattern:@"#\\w\\w*" options:NSRegularExpressionCaseInsensitive error:nil]; NSArray *hashtagRanges = [hashtagDetector matchesInString:string options:NSMatchingWithoutAnchoringBounds range:NSMakeRange(0, string.length)]; return hashtagRanges; } +(NSUInteger)numberOfHashtagsInString:(NSString *)string { NSRegularExpression *hashtagDetector = [[NSRegularExpression alloc] initWithPattern:@"#\\w\\w*" options:NSRegularExpressionCaseInsensitive error:nil]; NSUInteger numberOfHashtags = [hashtagDetector numberOfMatchesInString:string options:NSRegularExpressionCaseInsensitive range:NSMakeRange(0, string.length)]; return numberOfHashtags; } 
+6
source

Another way I decided to do this is as follows.

In the function - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text I place a listener for the dialed #, which starts writing down the characters following the hash until the user types the space in which it is flushed.

 if ([text isEqualToString:@"#"]) { recordingHashTag = YES; startParse = range.location; }else if ([text isEqualToString:@" "]) { currentHashTag = nil; recordingHashTag = NO; theTable.hidden = YES; } if (recordingHashTag == YES) { NSString *value; if (startParse > [textView.text length] - startParse) { value = [textView.text substringWithRange:NSMakeRange(startParse, [textView.text length] - startParse)]; [self filterHashTagTableWithHash:value]; } } 

If BOOL recordingHashTag set to YES , I pass a substring containing hashtag text to a function that looks for a pre-populated hashtag array. If there is a match, he adds this entry to the filtered hashtag array that he uses to populate the tableview on the fly.

 -(void)filterHashTagTableWithHash:(NSString *)hash{ [self.filterHashTagArray removeAllObjects]; for (NSString *hashTag in self.hashTagArray ){ NSRange result = [hashTag rangeOfString:hash options:NSCaseInsensitiveSearch]; if (result.location != NSNotFound) { [filterHashTagArray addObject:hashTag]; } } if (filterHashTagArray.count) { theTable.hidden = NO; }else{ theTable.hidden = YES; } [self.theTable reloadData]; } 

The final step is to insert the hash tag when the user clicks on an entry in the table.

  - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ UITableViewCell *cell = (UITableViewCell*)[self tableView:theTable cellForRowAtIndexPath:indexPath]; NSString *newString = [textViewComment.text stringByReplacingCharactersInRange:NSMakeRange(startParse, [textViewComment.text length] - startParse) withString:cell.textLabel.text]; textViewComment.text = newString; } 

Just remember to clear your variables when the user pays attention to the middle hash tag.

+3
source

Source: https://habr.com/ru/post/1383224/


All Articles