Прикосновение к слову в UILabel/UITextView

Что я хотел бы сделать, так это создать компонент текстового контейнера, который может указывать, что является ближайшим словом, когда к нему прикасаются (т.е. слово «за» точкой касания).

Сначала я создал подкласс UILabel и переопределил метод touchesEnded:withEvent: для определения затронутой CGPoint. Я также написал метод, который вычисляет соответствующий «кадр» (CGRect) каждого слова текста, используя sizeWithFont:forWidth:lineBreakMode:. С затронутой CGPoint и этим кадром я могу определить, какое слово на самом деле было затронуто. Но метод вычисления фрейма работает только с однострочным текстом.

Итак, теперь мне нужно знать, какая часть текста находится в данной строке (т. е. как текст был разделен), чтобы я мог вычислить правильное левое и верхнее поля каждого слова.

Любая идея, как я могу получить это? Или, может быть, у вас есть более простое решение для достижения этой цели? К сожалению, этот пост не очень помог..... .


person AgentCorleone    schedule 10.01.2012    source источник


Ответы (3)


(В вашем связанном посте есть ссылка на пример проекта кода, который действительно содержит полезный пример кода, но я также опишу для вас процесс здесь.)

Короче говоря, вам нужно будет использовать Core Text, который представляет собой усовершенствованную платформу Apple для обработки текста на основе C, которая поддерживает все сложные текстовые макеты в iOS и OS X.

Полный код будет несколько сложным, но основные методы, на которые вам стоит обратить внимание:

CTFramesetterCreateWithAttributedString() — используйте это в сочетании с NSAttributedString, который вы получите из текста вашей метки — для создания фреймсеттера

CTFramesetterCreateFrame() — используйте это, чтобы получить CTFrameRef для вашего текста из вышеуказанного фреймсеттера. Для этого вам нужно будет создать CGPathRef, используя границы вашей метки.

CTFrameGetLines(), CTFrameGetLineOrigins() — используйте их, чтобы получить CTLineRefs, соответствующие набранным строкам, и координаты начала линий соответственно, затем используйте CTLineGetStringIndexForPosition(), чтобы найти индекс символа в месте касания.

Затем вы можете использовать этот индекс символов (в системе отсчета строки), чтобы работать в обратном направлении и найти фактический символ/слово/и т. д. в вашей полной строке.

Не забывайте, что дело осложняется парой вопросов:

  1. Если вы используете собственный рисунок UILabel, вам придется позаботиться о том, чтобы идеально соответствовать вашим метрикам набора текста, что может быть громоздким, поскольку большинство объектов (например, CTFontRef) не связаны бесплатным мостом со своими аналогами UIKit. Реализация собственного чертежа иногда может быть проще, что гарантирует соответствие показателей.

  2. Базовый текст использует инвертированную систему координат по отношению к обычной системе рисования iOS. Если вы получаете дурацкие результаты, и особенно если вы рисуете сами, на это стоит обратить внимание.

Не самая простая задача в мире, но далеко не невыполнимая. Удачи!

person Conrad Shultz    schedule 10.01.2012
comment
На самом деле, я хотел бы избежать рисования текста самостоятельно, поскольку это кажется немного накладным, учитывая первоначальную потребность. Я рассмотрю ключи-функции CoreText, которые вы дали, спасибо! - person AgentCorleone; 11.01.2012

Немного поискав, я написал код для этого. Код будет работать для UITextView и UILabel.
Просто скачайте VSWordDetector.zip, разархивируйте его и перетащите папку VSWordDetector в свой проект.
В вашем классе ViewController есть два файла VSWordDetector.h и VSWordDetector.m
#import VSWordDetector.h.

@property (strong, nonatomic) VSWordDetector *wordDetector;

Примечание. Сделайте так, чтобы его свойство не воспринималось как локальное.

Теперь он готов для вас, просто добавьте его на textViews или Labels

-(void)viewDidLoad
{
   self.wordDetector = [[VSWordDetector alloc] initWithDelegate:self];
   [self.wordDetector addOnView:textView];
   [self.wordDetector addOnView:label];
}

-(void)wordDetector:(VSWordDetector *)wordDetector detectWord:(NSString *)word
{
   NSLog(@"Detected Word: %@", word);
}

Этот метод делегата будет вызываться при нажатии на подключенную метку или текстовое представление.

EDIT: пример кода для VSWordDetector< /сильный>.

РЕКОМЕНДУЕМОЕ ИЗМЕНЕНИЕ: Если вы не хотите загружать пример кода, вот код для обоих файлов. См. этот основной файл VSWordDetector.

person TheTiger    schedule 05.02.2014
comment
Привет . Я пытался использовать ваш код, но кран не обнаружен. Я выполнил шаги, которые вы дали, не могли бы вы сказать мне, где я ошибаюсь? - person Nijil Nair; 26.03.2014
comment
@NijilNair Извините, но я не могу сказать, где вы ошибаетесь. Итак, я сделал образец, см. Редактировать часть моего ответа. - person TheTiger; 26.03.2014
comment
Я не очень люблю почтовый код. Добавьте соответствующие части VSWordDetector сюда или вставьте код на github. - person Sulthan; 15.04.2014
comment
@Sulthan - заархивированный код - это отдельный код. Я сделал образец, который поможет первокурсникам. И голосовать против только тогда, когда мой код не работает и у него есть какая-то проблема. - person TheTiger; 15.04.2014
comment
@Sulthan - Как я уже сказал, первокурсники в некоторых случаях не могут получить объяснения. Мне не нравится делать образцы и предоставлять их другим, но для этого я должен был сделать это, чтобы люди поняли. - person TheTiger; 16.04.2014
comment
@Sulthan - я не вставлял весь код, потому что он слишком длинный. - person TheTiger; 16.04.2014
comment
Я счел совершенно несправедливым, что этот ответ получил оценку -1 до того, как я проголосовал за него. Он отлично отвечает на вопрос и действительно хорошо работает. Однако я согласен с правильным форматированием Stackoverflow. Так что было бы хорошо, если бы @TheTiger мог переформатировать так, как предложили комментаторы выше, чтобы этот ответ мог получить заслуженную оценку. - person Chris Harrison; 30.04.2014
comment
@ChrisHarrison - Спасибо ... На самом деле причина предоставления ссылки на образец заключается в том, что код слишком длинный, чтобы вставлять его сюда. Если я это сделаю, это сделает его длинным скроллером для посетителя. И есть много ответов, которые просто дают ссылку на пример кода для чужого кода, даже если я дал ссылку на свой собственный пример кода. Во всяком случае, я дал файлы .h и .m в виде текста, как вы предложили. - person TheTiger; 01.05.2014
comment
Это действительно полезно. Однако, поскольку этот подход предполагает, что текст выровнен по левому краю, если текст центрирован в метке, он работает неправильно :( - person rordulu; 27.08.2014

Хотя это старый вопрос, но я подумал, что это может помочь.

Поскольку изучение основного текста было огромным, я выбрал GLTapDemo от German Laullon.

С некоторыми изменениями это отлично работает для обнаружения прикосновения к слову в UILabel.

person Madhur Rawat    schedule 08.08.2013
comment
Я пробовал и решение VSWordDetector, и это решение, и обнаружил, что оно работает более эффективно для моего варианта использования. - person Andrew Church; 16.05.2015