Для UILabel
я хотел бы узнать, какой индекс символа в определенный момент получен из события касания. Я хотел бы решить эту проблему для iOS 7 с помощью Text Kit.
Поскольку UILabel не предоставляет доступ к своему NSLayoutManager
, я создал свой собственный на основе конфигурации UILabel
следующим образом:
- (void)textTapped:(UITapGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateEnded) {
CGPoint location = [recognizer locationInView:self];
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:self.attributedText];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[textStorage addLayoutManager:layoutManager];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:self.bounds.size];
[layoutManager addTextContainer:textContainer];
textContainer.maximumNumberOfLines = self.numberOfLines;
textContainer.lineBreakMode = self.lineBreakMode;
NSUInteger characterIndex = [layoutManager characterIndexForPoint:location
inTextContainer:textContainer
fractionOfDistanceBetweenInsertionPoints:NULL];
if (characterIndex < textStorage.length) {
NSRange range = NSMakeRange(characterIndex, 1);
NSString *value = [self.text substringWithRange:range];
NSLog(@"%@, %zd, %zd", value, range.location, range.length);
}
}
}
Приведенный выше код находится в подклассе UILabel
с UITapGestureRecognizer
, настроенным для вызова textTapped:
(Gist).
Результирующий индекс символа имеет смысл (увеличивается при касании слева направо), но не является правильным (последний символ достигается примерно на половине ширины метки). Похоже, что размер шрифта или размер текстового контейнера настроены неправильно, но проблема не найдена.
Я бы очень хотел, чтобы мой класс был подклассом UILabel
вместо использования UITextView
. Кто-нибудь решил эту проблему для UILabel
?
Обновление: я потратил билет DTS на этот вопрос, и инженер Apple порекомендовал переопределить drawTextInRect:
UILabel
реализацией, которая использует мой собственный менеджер компоновки, подобный этому фрагменту кода:
- (void)drawTextInRect:(CGRect)rect
{
[yourLayoutManager drawGlyphsForGlyphRange:NSMakeRange(0, yourTextStorage.length) atPoint:CGPointMake(0, 0)];
}
Я думаю, что будет много работы, чтобы мой собственный менеджер компоновки синхронизировался с настройками этикетки, поэтому я, вероятно, выберу UITextView
, несмотря на то, что предпочитаю UILabel
.
Обновление 2: я все-таки решил использовать UITextView
. Целью всего этого было обнаружение нажатий на встроенные в текст ссылки. Я пытался использовать NSLinkAttributeName
, но эта настройка не запускала обратный вызов делегата при быстром нажатии на ссылку. Вместо этого вы должны нажимать на ссылку в течение определенного времени — очень раздражает. Поэтому я создал CCHLinkTextView, у которого нет этой проблемы.
textContainer.lineFragmentPadding = 0;
, которая отсутствует в вашем образце, но присутствует в ответах ниже @Alexey Ishkov и @Kai Burghardt. Мне не пришлось хакнуть containerSize с номером 100. - person koen   schedule 19.02.2017