Предложить # теги при наборе текста (например, Twitter) для iPhone UITextView - PullRequest
5 голосов
/ 26 ноября 2011

Я бы создал приложение, которое использует хэштеги, такие как Twitter или Tweetbot. Когда вы печатаете сообщение, если вы набираете символ хэштега, я бы хотел предложить теги, которые соответствуют текущему, который вы печатаете.

Я уже понял, как заставить UITableView появляться и отображать список хэштегов, но я не могу понять, как сделать следующее:

  1. Получить NSRange текущего набираемого слова,
  2. Проверьте, отформатирован ли этот диапазон как хэштег (NSRegularExpression @"#\\w\\w*")
  3. (С этого момента я получил код для поиска подходящих хэштегов и отображения их в UITableView)

Может кто-нибудь помочь мне с шагами 1 и 2? Я думал об использовании textViewDidChange:, но я обеспокоен тем, что производительность приложения может снизиться, если я постоянно запускаю методы каждый раз, когда меняются символы.

Спасибо!

Ответы [ 2 ]

8 голосов
/ 04 декабря 2011

Я понял это!Я использовал методы textViewDidChange: и textViewDidChangeSelection:.

Чтобы получить NSRange текущего набираемого хэштега, я запустил цикл for поверх совпадений NSRegularExpression в текстовой строке.,Оттуда я использовал NSLocationInRange, чтобы узнать, пересекает ли текущая позиция курсора какой-либо из хэштегов.

Вот код:

//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's hide the tag table.
        if ([tagsToDisplay count] == 0) 
        {
            [self hideTagTable];
            return;
        }

    }

Класс StringChecker является пользовательскимчто я написал, он просто имеет методы класса, которые анализируют строки.Я сделал StringChecker классом, потому что методы используются в нескольких местах приложения.Вот метод:

    #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;
}
4 голосов
/ 07 июня 2013

Другой способ, который я понял, заключается в следующем.

В функции - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text я помещаю слушателя для набираемого #, который начинает записывать символы после хеша, пока пользователь не введет пробел, и в этот момент он сбрасывается.

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];
    }
}

Если для BOOL recordingHashTag установлено значение YES, я передаю substring, содержащий текст хэштега, в функцию, которая ищет предварительно заполненный массив хэштегов. Если есть совпадение, он добавляет эту запись в отфильтрованный массив хэштегов, которые он использует для заполнения tableview на лету.

-(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];
}

Последний шаг - вставить хэш-тег, когда пользователь нажимает на запись в таблице.

    - (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;
}

Только не забудьте очистить ваши переменные, когда пользователь забивает середину хеш-тега.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...