Lower Level Text-Handling Technologies

Большинство приложений может использовать высокоуровневые текстовые классы дисплея и текстовый Набор для всей их текстовой обработки. У Вас могло бы быть приложение, однако, который требует более низкого уровня программируемые интерфейсы от Базового текста, Базовой Графики, и Базовых платформ Анимации, а также другого APIs в самом UIKit.

Простое текстовое получение

В дополнение к классам UIKit для отображения и редактирования текста, iOS также включает несколько способов составить текст непосредственно на экране. Самый простой и самый эффективный способ нарисовать простые строки использует дополнения UIKit к NSString класс, который находится в названной категории UIStringDrawing. Эти расширения включают методы для рисования строк с помощью множества атрибутов везде, где Вы хотите их на экране. Существуют также методы для вычислений размера представленной строки перед фактическим рисованием его который может помочь Вам разметить свое содержимое приложения более точно.

Методы UIStringDrawing нарисуйте строки в данной точке (для одних строк текста) или в указанном прямоугольнике (для многократных строк). Можно передать в атрибутах, используемых в рисовании — например, шрифт, режим разрыва строки и базовая корректировка. Методы UIStringDrawing позвольте Вам корректировать позицию представленного текста точно и смешивать его с остальной частью содержания Вашего представления. Они также позволяют Вам вычислить ограничительный прямоугольник для своего текста заранее на основе желаемых атрибутов шрифта и атрибутов стиля.

Можно также использовать CATextLayer класс Базовой Анимации, чтобы сделать простое текстовое получение. Объект этого класса хранит простую строку или приписанную строку как ее содержание и предлагает ряд атрибутов, влияющих на то содержание, такое как шрифт, размер шрифта, цвет текста и поведение усечения. Преимущество CATextLayer это (быть подклассом CALayer) его свойства по сути способны к анимации. Базовая Анимация связана с платформой QuartzCore. Поскольку экземпляры CATextLayer знайте, как привлечь себя в текущем графическом контексте, Вы не должны выпускать явные команды рисования при использовании тех экземпляров.

Для получения информации о рисующих строку расширениях NSString, см. NSString UIKit Дополнительная Ссылка. Узнать больше CATextLayer, CALayer, и другие классы Базовой Анимации, считайте Базовое Руководство по программированию Анимации.

Базовый текст

Базовый текст является технологией для расположения пользовательского текста и управления шрифтом. У разработчиков приложений обычно нет потребности использовать Базовый текст непосредственно. Текстовый Набор создается поверх Базового текста, давая ему те же преимущества, такие как скорость и сложная типографская возможность. Кроме того, текстовый Набор обеспечивает много инфраструктуры, которую необходимо создать для себя при использовании Базового текста.

Однако Базовый текстовый API доступен для разработчиков, которые должны использовать его непосредственно. Это предназначается, чтобы использоваться приложениями, имеющими их собственные механизмы расположения — например, текстовой процессор, имеющий его собственный механизм макета страницы, может использовать Базовый текст, чтобы генерировать глифы и расположить их друг относительно друга.

Базовый текст реализован как платформа, публикующая API, подобный той из Базовой Основы — подобный в этом, это является процедурным (ANSI C), но основывается на подобных объекту непрозрачных типах. Этот API интегрируется и с Базовой Основой и с Базовой Графикой. Например, Базовый текст использует Базовую Основу и Базовые Графические объекты во многих параметрах ввода и вывода. Кроме того, потому что много Базовых объектов Основы “бесплатные соединенный мостом” с их дубликатами в платформе Основы, можно использовать некоторые объекты Основы в параметрах Базовых текстовых функций.

Базовый текст имеет две главных части: механизм расположения и технология создания шрифтов, каждый поддержанный ее собственным набором непрозрачных типов.

Базовое текстовое расположение непрозрачные типы

Базовый текст требует двух объектов, непрозрачные типы которых не являются собственными к нему: приписанная строка (CFAttributedStringRef) и графический контур (CGPathRef). Объект приписанной строки инкапсулирует строку, поддерживающую отображаемый текст, и включает свойства (или, «атрибуты»), которые определяют стилистические аспекты символов в строке — например, шрифт и цвет. Графический контур определяет форму кадра текста, который эквивалентен абзацу.

Базовые Текстовые объекты во время выполнения формируют иерархию, которая является отражающей из уровня обрабатываемого текста (см. рисунок 10-1). Наверху этой иерархии объект framesetter (CTFramesetterRef). С приписанной строкой и графическим контуром, как введено, framesetter генерирует один или несколько кадров текста (CTFrameRef). Поскольку текст размечается в кадре, framesetter применяет стили абзаца к нему, включая такие атрибуты как выравнивание, позиции табуляции, межстрочный интервал, добавление отступа и повреждающий строку режим.

Для генерации кадров framesetter вызывает объект наборного устройства (CTTypesetterRef). Наборное устройство преобразовывает символы в приписанной строке к глифам и вмещает те глифы в строки, заполняющие текстовую рамку. (Глиф является графической формой, используемой для представления символа.) Строка в кадре представлена a CTLine объект (CTLineRef). A CTFrame объект содержит массив CTLine объекты.

A CTLine объект, в свою очередь, содержит массив выполнений глифа, представленных объектами CTRunRef ввести. Выполненный глиф является серией последовательных глифов, имеющих те же атрибуты и направление. Несмотря на то, что наборное устройство возражает возвратам CTLine объекты, это составляет те строки из массивов выполнений глифа.

  Текстовые объекты расположения Ядра рисунка 10-1

Используя функции CTLine непрозрачный тип, можно чертить линию текста от приписанной строки, не имея необходимость проходить через CTFramesetter объект. Вы просто располагаете источник текста на текстовой базовой линии и запрашиваете объект линии нарисовать себя.

Базовый шрифт текста непрозрачные типы

Шрифты важны для обработки текста в Базовом тексте. Объект наборного устройства использует шрифты (вместе с приписанной строкой источника), чтобы преобразовать глифы из символов и затем расположить те глифы относительно друг друга. Графический контекст является центральным к шрифтам в Базовом тексте. Можно использовать функции графического контекста, чтобы установить текущий шрифт и нарисовать глифы; или можно создать a CTLine объект от приписанной строки и использования ее функции для вовлечения графического контекста. Базовая система Шрифта текста обрабатывает Шрифты юникода исходно.

Система шрифта включает объекты трех непрозрачных типов: CTFont, CTFontDescriptor, и CTFontCollection:

  • Объекты шрифта (CTFontRef) инициализируются с размером точки и определенными характеристиками (от матрицы преобразования). Можно запросить объект шрифта для его отображения символа к глифу, его кодирования, данных глифа и метрик, таких как подъем, продвижение, и т.д. Базовый текст также предлагает вызванное расположение каскадом шрифта механизма автоматической замены шрифтов.

  • Объекты дескриптора шрифта (CTFontDescriptorRef) обычно используются для создания объектов шрифта. Вместо того, чтобы иметь дело со сложной матрицей преобразования, они позволяют Вам указывать словарь атрибутов шрифта, включающих такие свойства как имя PostScript, семейство шрифтов и стиль и черты (например, полужирный или курсивный).

  • Объекты коллекции шрифта (CTFontCollectionRef) группы дескрипторов шрифта, предоставляющих услуги, такие как перечисление шрифта и доступ к наборам глобального и пользовательского шрифта.

Возможно преобразовать UIFont объекты к CTFont объекты путем вызова CTFontCreateWithName, передача имени шрифта и размера точки, инкапсулировавшего UIFont объект.

Базовое графическое текстовое получение

Базовая Графика (или Кварц) является системной платформой, обрабатывающей двумерную обработку изображений на самом низком уровне. Текстовое получение является одной из своих возможностей. Обычно, потому что Базовая Графика является столь низкоуровневой, рекомендуется использовать одну из других технологий системы для рисования текста. Однако, если обстоятельства требуют его, можно составить текст с Базовой Графикой.

Вы выбираете шрифты, устанавливаете текстовые атрибуты и составляете текст с помощью функций непрозрачного типа CGContext. Например, можно вызвать CGContextSelectFont установить шрифт, используемый, и затем вызвать CGContextSetFillColor установить цвет текста. Вы тогда устанавливаете текстовую матрицу (CGContextSetTextMatrix) и нарисуйте текстовое использование CGContextShowGlyphsAtPoint.

Для получения дополнительной информации об этих функциях и их использовании, посмотрите Кварц 2D Руководство по программированию и Базовая Графическая Ссылка Платформы.

Регулярные выражения уровня основы

NSString класс платформы Основы включает простой программируемый интерфейс для регулярных выражений. Вы вызываете один из трех методов, возвращающих диапазон, передающий в определенной постоянной опции и строка регулярного выражения. Если существует соответствие, метод возвращает диапазон подстроки. Опция NSRegularExpressionSearch постоянный, который имеет тип битовой маски NSStringCompareOptions; эта константа говорит методу ожидать образец регулярного выражения, а не литеральную строку как поисковое значение. Поддерживаемый синтаксис регулярного выражения то, что определен ICU (Международные Компоненты для Unicode).

NSString методы для регулярных выражений являются следующим:

Если Вы указываете NSRegularExpressionSearch опция в этих методах, единственном другом NSStringCompareOptions опции, которые можно указать, NSCaseInsensitiveSearch и NSAnchoredSearch. Если поиск регулярного выражения не находит соответствие, или синтаксис регулярного выражения уродлив, эти методы возвращаются NSRange структура со значением {NSNotFound, 0}.

Перечисление 10-1 дает пример использования NSString регулярное выражение API.

Перечисление 10-1  , Находящее подстроку с помощью регулярного выражения

    // finds phone number in format nnn-nnn-nnnn
    NSRange r;
    NSString *regEx = @"[0-9]{3}-[0-9]{3}-[0-9]{4}";
    r = [textView.text rangeOfString:regEx options:NSRegularExpressionSearch];
    if (r.location != NSNotFound) {
        NSLog(@"Phone number is %@", [textView.text substringWithRange:r]);
    } else {
        NSLog(@"Not found.");
    }

Поскольку эти методы возвращают единственное значение диапазона для подстроки, соответствующей образец, определенные возможности регулярного выражения библиотеки ICU или не доступны или должны быть программно добавлены. Кроме того, NSStringCompareOptions опции, такие как обратный поиск, числовой поиск и нечувствительный к диакритическому знаку поиск не доступны и получают группы, не поддерживаются.

При тестировании возвращенного диапазона необходимо знать об определенных поведенческих различиях между поисками на основе литеральных строк и поисками на основе образцов регулярного выражения. Некоторые образцы могут успешно соответствовать и возвратиться NSRange структура с a length из 0 (когда location поле представляет интерес). Другие образцы могут успешно соответствовать против пустой строки или, в тех методах с параметром диапазона, с диапазоном поиска нулевой длины.

Поддержка регулярного выражения ICU

В случае, если NSString поддержка регулярных выражений не достаточна для Ваших потребностей, измененная версия библиотек от ICU 4.2.1 включена в iOS в BSD (неплатформа) уровень системы. ICU (Международные Компоненты для Unicode) является проектом с открытым исходным кодом для поддержки Unicode и интернационализации программного обеспечения. Установленная версия ICU включает те заголовочные файлы, необходимые для поддержки регулярных выражений, вместе с некоторыми модификациями, связанными с теми интерфейсами, а именно:

Можно считать документацию API ICU 4.2 и руководство пользователя в http://icu-project .org/apiref/icu4c/index.html.

Простой текстовый ввод

Приложение, хотящее вывести на экран и текст процесса, не ограничивается текстом и веб-объектами платформы UIKit. Это может реализовать пользовательские представления, которые способны к чему-либо от простой текстовой записи для объединения обработки текста и пользовательского ввода. Через доступные интерфейсы программирования эти приложения могут получить функции, такие как расположение пользовательского текста, многоступенчатый ввод, автоисправление, пользовательские клавиатуры и проверка правописания.

Можно реализовать пользовательские представления, позволяющие пользователям вводить текст в точке вставки и удалять символы перед той точкой вставки, когда они касаются клавиши Delete. Приложение мгновенного обмена сообщениями, например, могло иметь представление, позволяющее пользователям вводить свою часть разговора.

Можно получить эту возможность простой текстовой записи путем разделения на подклассы UIView, или любой другой класс представления, наследовавшийся от UIResponder, и принятие UIKeyInput протокол. Когда экземпляр Вашего класса представления становится первым респондентом, UIKit выводит на экран системную клавиатуру. UIKeyInput самостоятельно принимает UITextInputTraits протокол, таким образом, можно установить тип клавиатуры, тип клавиши Return и другие атрибуты клавиатуры.

Принять UIKeyInput, необходимо реализовать эти три метода, которые это объявляет: hasText, insertText:, и deleteBackward. Чтобы сделать фактическое получение текста, можно использовать любую из технологий, полученных в итоге в этой главе. Однако для простого текстового ввода, такой что касается одной строки текста в пользовательском элементе управления, UIStringDrawing и CATextLayer APIs является самым надлежащим.

Перечисление 10-2 иллюстрирует UIKeyInput реализация пользовательского класса представления. textStore свойство в этом примере NSMutableString объект, служащий запоминающим устройством текста. Реализация или добавляет или удаляет последний знак в строке (в зависимости от того, нажимаются ли алфавитно-цифровой ключ или клавиша Delete), и затем перерисовывает textStore.

Перечисление 10-2  Реализовывая простую текстовую запись

- (BOOL)hasText {
    if (textStore.length > 0) {
        return YES;
    }
    return NO;
}
 
- (void)insertText:(NSString *)theText {
    [self.textStore appendString:theText];
    [self setNeedsDisplay];
}
 
- (void)deleteBackward {
    NSRange theRange = NSMakeRange(self.textStore.length-1, 1);
    [self.textStore deleteCharactersInRange:theRange];
    [self setNeedsDisplay];
}
 
- (void)drawRect:(CGRect)rect {
    CGRect rectForText = [self rectForTextWithInset:2.0]; // custom method
    [self.theColor set];
    UIRectFrame(rect);
    [self.textStore drawInRect:rectForText withFont:self.theFont];
}

Для фактического рисования текста в представлении этот код использует drawInRect:withFont: от UIStringDrawing категория на NSString.

Связь с системой ввода текста

Система ввода текста iOS управляет клавиатурой. Это интерпретирует касания как нажатия определенных ключей в определенных клавиатурах, подходящих для определенных языков. Это тогда отправляет связанный символ в целевое представление для вставки. Как объяснено в Простом текстовом Вводе, классы представления должны принять UIKeyInputпротокол вставить и удалить символы в каре (точка вставки).

Однако система ввода текста делает больше, чем простая текстовая запись. Например, это управляет автоисправлением и многоступенчатым вводом, которые все основаны на текущем выборе и контексте. Многоступенчатый ввод текста требуется для идеографических языков, таких как Кандзи (японский язык) и Hanzi (китайцы), берущие ввод с фонетических клавиатур. Для получения этих функций представление пользовательского текста должно связаться с системой ввода текста путем принятия UITextInput протокол и реализация связанных классов клиентской стороны и протоколов.

Следующий раздел описывает общую ответственность представления пользовательского текста, связывающегося с системой ввода текста. Экскурсия по Реализации UITextInput исследует самые важные классы и методы типичной реализации UITextInput.

Обзор клиентской стороны ввода текста

Класс, хотящий связаться с системой ввода текста, должен принять UITextInput протокол. Класс должен наследоваться от UIResponder и в большинстве случаев пользовательское представление.

Текстовое представление должно сделать свое собственное текстовое расположение и управление шрифтом; с этой целью Базовая текстовая платформа рекомендуется. (Базовый текст дает обзор Базового текста.) Класс должен также принять и реализовать UIKeyInput протокол и должен установить необходимые свойства UITextInputTraits протокол.

Общая архитектура клиента и системные стороны системы ввода текста схематически изображаются на рисунке 10-2.

  Пути рисунка 10-2 связи с системой ввода текста

Системные вызовы ввода текста UITextInput методы, которые реализует текстовое представление. Многие из этих методов запрашивают информацию об определенных текстовых позициях, и текстовые диапазоны от текста просматривают и пасуют назад ту же информацию к классу в других вызовах метода. Причины этих обменов текстовыми позициями и текстовыми диапазонами получены в итоге в Задачах Объекта UITextInput.

Текстовые позиции и текстовые диапазоны в системе ввода текста представлены экземплярами пользовательских классов. Текстовые Позиции и текстовые Диапазоны обсуждают эти объекты более подробно.

Текстовое представление также поддерживает ссылки на токенизатор и входного делегата. Текстовое представление вызывает методы, объявленные UITextInputDelegate протокол для уведомления предоставленного системой ввода делегирует о внешних изменениях в тексте и выборе. Система ввода текста связывается с объектом токенизатора определить гранулярность единиц текста — например, символ, слово и абзац. Токенизатор является объектом, принимающим UITextInputTokenizer протокол. Текстовое представление включает свойство (объявленный UITextInput) это содержит ссылку на токенизатор.

Текстовые позиции и текстовые диапазоны

Клиентское приложение должно создать два класса, экземпляры которых представляют позиции и диапазоны текста в текстовом представлении. Эти классы должны быть подклассами UITextPosition и UITextRange.

Несмотря на то, что UITextPosition самостоятельно не объявляет методов или свойств, это - основная часть информации, обменянной между текстовым документом и системой ввода текста. Система ввода текста требует объекта представлять расположение в тексте вместо, скажем, целого числа или структуры. Кроме того, a UITextPosition когда строка, поддерживающая текст, имеет различное смещение к той позиции, объект может служить практической цели путем представления позиции в видимом тексте. Когда строка содержит невидимые символы форматирования, такой как с RTF и документами HTML или внедренными объектами, такими как присоединение, это происходит. Пользовательское UITextPosition класс может составить эти невидимые символы при определении местоположения строковых смещений видимых символов. В самом простом случае — документе простого текста без внедренных объектов — пользовательское UITextPosition объект может инкапсулировать единственное смещение или индексировать целое число.

UITextRange объявляет простой интерфейс, в котором два из его свойств запускаются и заканчиваются пользовательский UITextPosition объекты. Третье свойство содержит булево значение, указывающее, пуст ли диапазон (т.е. не имеет никакой длины).

Задачи объекта UITextInput

Класс, принимающий UITextInput протокол требуется, чтобы реализовывать большинство методов и свойств протокола. За немногим исключением эти методы берут пользовательский UITextPosition или UITextRange объекты как параметры или возврат один из этих объектов. Во время выполнения текстовая система вызывает эти методы и, снова в почти всех случаях, ожидает некоторый объект или значение назад.

Текстовое представление должно присвоить текстовые позиции свойствам, отмечающим начало и конец отображаемого текста. Кроме того, это должно также поддержать диапазон в настоящее время выделенного текста и диапазон в настоящее время отмечаемого текста, если таковые имеются. Отмеченный текст, который является частью многоступенчатого ввода текста, представляет временно вставленный текст, который должен все же подтвердить пользователь. Это разрабатывается отличительным способом. Диапазон отмеченного текста всегда содержит в нем диапазон выделенного текста, который мог бы быть диапазоном символов или каре.

Методы реализованы a UITextInput объект может быть разделен на отличительные задачи:

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

  • Вычислительные текстовые диапазоны и текстовые позиции. Создайте и возвратите a UITextRange объект (или, просто, текстовый диапазон) данный две текстовых позиции; или создайте и возвратите a UITextPosition объект (или, просто, текстовая позиция) данный текстовую позицию и смещение.

  • Оценка текстовых позиций. Сравните две текстовых позиции или возвратите смещение от одной текстовой позиции до другого.

  • Ответ на вопросы расположения. Определите текстовую позицию или текстовый диапазон путем расширения в данном направлении макета.

  • Тестирование хита. Учитывая точку, возвратите самую близкую текстовую позицию или текстовый диапазон.

  • Возврат прямоугольников для текстовых диапазонов и текстовых позиций. Возвратите прямоугольник, включающий текстовый диапазон или прямоугольник в текстовой позиции каре.

UITextInput объект мог бы также принять решение реализовать один или несколько дополнительных методов протокола. Они позволяют ему возвратить стили текста (шрифт, цвет текста, цвет фона) начинающийся в указанной текстовой позиции и согласовать позицию видимого текста и символьное смещение (для тех UITextPosition объекты, где эти значения не являются тем же).

Когда изменения происходят в текстовом представлении вследствие внешних причин — т.е. они не вызываются вызовами от системы ввода текста — UITextInput объект должен отправить textWillChange:, textDidChange:, selectionWillChange:, и selectionDidChange: сообщения входному делегату (который это содержит ссылку на). Например, когда пользователи касаются текстового представления, и Вы устанавливаете диапазон выделенного текста для размещения точки вставки под пальцем, Вы отправили бы selectionWillChange: перед изменением выбранного диапазона, и Вы отправляете selectionDidChange: после изменения диапазона.

Токенизаторы

Токенизаторы являются объектами, определяющими, является ли текстовая позиция в или на границе единицы текста с данной гранулярностью. Когда запрошено системой ввода текста, токенизатор возвращает диапазоны единиц текста с данной гранулярностью или граничной текстовой позицией для единицы текста с данной гранулярностью. В настоящее время определяемые гранулярности являются символом, словом, предложением, абзацем, строкой и документом; enum константы UITextGranularity тип представляет эти гранулярности. Гранулярности единиц текста всегда оцениваются в отношении хранения или направления макета.

Система ввода текста использует токенизатор во множестве путей. Например, клавиатура могла бы потребовать, чтобы ценность последнего предложения контекста выяснила то, что пользователь пытается ввести. Или, если пользователь нажатие Option-left (на внешней клавиатуре), текстовая система запрашивает токенизатор для нахождения информации, которую это должно переместить в предыдущее слово.

Токенизатор является экземпляром класса, соответствующего UITextInputTokenizer протокол. UITextInputStringTokenizer класс обеспечивает базовое внедрение по умолчанию UITextInputTokenizer протокол, подходящий для всех поддерживаемых языков. При требовании токенизатора с полностью новой интерпретацией единиц текста переменной гранулярности необходимо принять UITextInputTokenizer и реализуйте все его методы. Иначе необходимо разделить на подклассы UITextInputStringTokenizer предоставить специфичную для приложения информацию о направлениях макета.

Когда Вы инициализируете a UITextInputStringTokenizer объект, Вы предоставляете его представление, принимающее UITextInput протокол. В свою очередь, UITextInput объект должен лениво создать свой объект токенизатора в методе получателя свойства токенизатора.

Экскурсия по реализации UITextInput

SimpleTextInput является простым приложением редактирования текста на основе Базового текста. Это имеет два пользовательских подкласса UIView. Один подкласс представления, SimpleCoreTextView, обеспечивает текстовое расположение и редактирующий поддержку с помощью Базового текста. Другой подкласс представления, EditableCoreTextView, принимает UIKeyInput протокол для включения ввода текста; это также принимает UITextInput протокол и создает и реализует связанные подклассы для передачи с системой ввода текста. EditableCoreTextView встраивает SimpleCoreTextView как переменная экземпляра, инстанцирует его и вызывает через к нему в большинстве UITextInput и UIKeyInput реализации метода.

Подклассы UITextPosition и UITextRange

EditableCoreTextView создает пользовательский подкласс UITextPosition вызванный IndexedPosition и пользовательский подкласс UITextRange вызванный IndexedRange. Эти подклассы просто инкапсулируют единственное индексное значение и NSRange оцените на основе двух из тех индексов. Перечисление 10-3 показывает объявление этих классов.

Перечисление 10-3  , объявляющее IndexedPosition и IndexedRange классы

@interface IndexedPosition : UITextPosition {
    NSUInteger _index;
    id <UITextInputDelegate> _inputDelegate;
}
@property (nonatomic) NSUInteger index;
+ (IndexedPosition *)positionWithIndex:(NSUInteger)index;
@end
 
@interface IndexedRange : UITextRange {
    NSRange _range;
}
@property (nonatomic) NSRange range;
+ (IndexedRange *)rangeWithNSRange:(NSRange)range;
 
@end

Оба класса объявляют, что методы фабрики классов продают экземпляры. Перечисление 10-4 показывает реализацию этих методов, а также методов, объявленных UITextRange класс.

Перечисление 10-4  реализовывая IndexedPosition и IndexedRange классы

@implementation IndexedPosition
@synthesize index = _index;
 
+ (IndexedPosition *)positionWithIndex:(NSUInteger)index {
    IndexedPosition *pos = [[IndexedPosition alloc] init];
    pos.index = index;
    return [pos autorelease];
}
 
@end
 
@implementation IndexedRange
@synthesize range = _range;
 
+ (IndexedRange *)rangeWithNSRange:(NSRange)nsrange {
    if (nsrange.location == NSNotFound)
        return nil;
    IndexedRange *range = [[IndexedRange alloc] init];
    range.range = nsrange;
    return [range autorelease];
}
 
- (UITextPosition *)start {
    return [IndexedPosition positionWithIndex:self.range.location];
}
 
- (UITextPosition *)end {
        return [IndexedPosition positionWithIndex:(self.range.location + self.range.length)];
}
 
-(BOOL)isEmpty {
    return (self.range.length == 0);
}
@end

Вставка и удаление текста

Текстовое представление, принимающее UITextInput протокол должен также принять UIKeyInput протокол. Это означает, что должно реализовать insertText:, deleteBackward, и hasText методы, как обсуждено в Простом текстовом Вводе. Поскольку EditableCoreTextView класс принимает UITextInput, это должно также поддержать выбранные и отмеченные текстовые диапазоны (т.е. текущая стоимость selectedTextRange и markedTextRange свойства), поскольку текст введен и удален.

Перечисление 10-5 иллюстрирует как EditableCoreTextView когда текст введен, делает это. Если существует отмеченный текст, когда символ вводится, это заменяет отмеченный текст символом путем вызова replaceCharactersInRange:withString: метод на отступающей непостоянной строке. Если существует выбранный диапазон текста, он заменяет символы в том диапазоне с вводимым символом. Иначе, метод вставляет вводимый символ в каре.

Перечисление 10-5  , Вставляющее ввод текста в хранение и обновляющее выбранные и отмеченные диапазоны

- (void)insertText:(NSString *)text {
    NSRange selectedNSRange = _textView.selectedTextRange;
    NSRange markedTextRange = _textView.markedTextRange;
 
    if (markedTextRange.location != NSNotFound) {
        [_text replaceCharactersInRange:markedTextRange withString:text];
        selectedNSRange.location = markedTextRange.location + text.length;
        selectedNSRange.length = 0;
        markedTextRange = NSMakeRange(NSNotFound, 0);
    } else if (selectedNSRange.length > 0) {
        [_text replaceCharactersInRange:selectedNSRange withString:text];
        selectedNSRange.length = 0;
        selectedNSRange.location += text.length;
    } else {
        [_text insertString:text atIndex:selectedNSRange.location];
        selectedNSRange.location += text.length;
    }
    _textView.text = _text;
    _textView.markedTextRange = markedTextRange;
    _textView.selectedTextRange = selectedNSRange;
}

Даже при том, что структура deleteBackward метод, реализованный EditableCoreTextView идентично insertText: метод, существуют надлежащие различия в том, как корректируются выбранные и отмеченные текстовые диапазоны. Другое различие то, что deleteCharactersInRange: метод вызывают на отступающей непостоянной строке, а не replaceCharactersInRange:withString:.

Возврат и замена текста диапазоном

Любое текстовое представление, связывающееся с системой ввода текста, когда требуется, должно возвратить указанный диапазон текста и заменить диапазон текста с данной строкой. Классы в нашем примере, EditableCoreTextView и SimpleCoreTextView, поддержите синхронизируемые копии отступающего строкового объекта (EditableCoreTextView как a NSMutableString объект). Реализации textInRange: и replaceRange:withText: в Перечислении 10-6 вызывают надлежащее NSString методы на отступающей строке для выполнения их существенных функций.

  Реализации перечисления 10-6 textInRange: и replaceRange:withText:

- (NSString *)textInRange:(UITextRange *)range
{
    IndexedRange *r = (IndexedRange *)range;
    return ([_text substringWithRange:r.range]);
}
 
- (void)replaceRange:(UITextRange *)range withText:(NSString *)text
{
    IndexedRange *r = (IndexedRange *)range;
    NSRange selectedNSRange = _textView.selectedTextRange;
    if ((r.range.location + r.range.length) <= selectedNSRange.location) {
        selectedNSRange.location -= (r.range.length - text.length);
    } else {
        // Need to also deal with overlapping ranges.
    }
    [_text replaceCharactersInRange:r.range withString:text];
    _textView.text = _text;
    _textView.selectedTextRange = selectedNSRange;
}

Когда text свойство SimpleCoreTextView изменения (как показано в реализации replaceRange:withText:), SimpleCoreTextView размечает текст снова и перерисовывает его с помощью Базовых текстовых функций.

Поддержание выбранных и отмеченных текстовых диапазонов

Поскольку операции редактирования выполняются на выбранном и отмеченном тексте, система ввода текста часто запрашивает, чтобы текстовый возврат представления и установил диапазоны выбранного и отмеченного текста. Перечисление 10-7 показывает как EditableCoreTextView возвращает диапазоны выбранного и отмеченного текста путем реализации методов получателя для selectedTextRange и markedTextRangeсвойства.

Перечисление 10-7  Возвращая диапазоны выбранного и отмеченного текста

- (UITextRange *)selectedTextRange {
    return [IndexedRange rangeWithNSRange:_textView.selectedTextRange];
}
 
- (UITextRange *)markedTextRange {
    return [IndexedRange rangeWithNSRange:_textView.markedTextRange];
}

Метод установщика для selectedTextRange в Перечислении 10-8 просто устанавливает диапазон выделенного текста на встроенном текстовом представлении. setMarkedText:selectedRange: метод более сложен, потому что, как можно вспомнить, диапазон отмеченного текста содержит в нем диапазон выделенного текста (даже если диапазон просто идентифицирует каре), и эти диапазоны должны быть согласованы для отражения ситуации после вставки текста.

Перечисление 10-8  , Устанавливающее диапазон выделенного текста и устанавливающее отмеченный текст

- (void)setSelectedTextRange:(UITextRange *)range
{
    IndexedRange *r = (IndexedRange *)range;
    _textView.selectedTextRange = r.range;
}
 
- (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange {
    NSRange selectedNSRange = _textView.selectedTextRange;
    NSRange markedTextRange = _textView.markedTextRange;
 
    if (markedTextRange.location != NSNotFound) {
        if (!markedText)
            markedText = @"";
        [_text replaceCharactersInRange:markedTextRange withString:markedText];
        markedTextRange.length = markedText.length;
    } else if (selectedNSRange.length > 0) {
        [_text replaceCharactersInRange:selectedNSRange withString:markedText];
        markedTextRange.location = selectedNSRange.location;
        markedTextRange.length = markedText.length;
    } else {
        [_text insertString:markedText atIndex:selectedNSRange.location];
        markedTextRange.location = selectedNSRange.location;
        markedTextRange.length = markedText.length;
    }
    selectedNSRange = NSMakeRange(selectedRange.location + markedTextRange.location,
        selectedRange.length);
 
    _textView.text = _text;
    _textView.markedTextRange = markedTextRange;
    _textView.selectedTextRange = selectedNSRange;
}

Обратите внимание на то, что EditableCoreTextView заменяет текст путем вызова replaceCharactersInRange:withString: метод на его непостоянном строковом объекте, который это тогда присваивает text свойство встроенного текстового представления.

Часто вызываемые методы UITextInput

Когда пользовательские символы текста на клавиатуре и информацию от объекта, принимающего, когда те символы вводят текстовое хранение и размечаются, система ввода текста запрашивают UITextInput протокол. Три из более часто вызываемых методов textRangeFromPosition:toPosition:, offsetFromPosition:toPosition:, и positionFromPosition:offset:.

Системные вызовы ввода текста positionFromPosition:offset: для получения позиции в тексте, это - данное смещение от другой позиции. Перечисление 10-9 показывает как EditableCoreTextView реализации этот метод (который включает проверку диапазона).

  Реализация перечисления 10-9 positionFromPosition:offset:

- (UITextPosition *)positionFromPosition:(UITextPosition *)position offset:(NSInteger)offset {
    IndexedPosition *pos = (IndexedPosition *)position;
    NSInteger end = pos.index + offset;
    if (end > _text.length || end < 0)
        return nil;
    return [IndexedPosition positionWithIndex:end];
}

offsetFromPosition:toPosition: метод должен удовлетворить противоположный запрос и возвратить значение, указывающее смещение между двумя текстовыми позициями. EditableCoreTextView реализации это как показано в Перечислении 10-10.

  Реализация перечисления 10-10 offsetFromPosition:toPosition:

- (NSInteger)offsetFromPosition:(UITextPosition *)from toPosition:(UITextPosition *)toPosition {
    IndexedPosition *f = (IndexedPosition *)from;
    IndexedPosition *t = (IndexedPosition *)toPosition;
    return (t.index - f.index);
}

Наконец, система ввода текста часто просит у текстового представления текстовый диапазон, падающий между двумя текстовыми позициями. Перечисление 10-11 показывает реализацию textRangeFromPosition:toPosition: это возвращает этот диапазон.

  Реализация перечисления 10-11 textRangeFromPosition:toPosition:

- (UITextRange *)textRangeFromPosition:(UITextPosition *)fromPosition
          toPosition:(UITextPosition *)toPosition {
    IndexedPosition *from = (IndexedPosition *)fromPosition;
    IndexedPosition *to = (IndexedPosition *)toPosition;
    NSRange range = NSMakeRange(MIN(from.index, to.index), ABS(to.index - from.index));
    return [IndexedRange rangeWithNSRange:range];
}

Возврат прямоугольников

Когда пользовательские типы на японском языке, система ввода текста отправляет, когда пузырь исправления появляется и firstRectForRange: и caretRectForPosition: к текстовому представлению. Цель обоих из этих методов состоит в том, чтобы возвратить прямоугольник, включающий или диапазон текста или каре, отмечающее точку вставки. EditableCoreTextView класс реализует первый из этих методов путем вызова метода его встроенного текстового представления, отображающего диапазон на прямоугольник включения (см. Перечисление 10-12). Прежде, чем возвратить прямоугольник, это преобразовывает его в систему локальной координаты.

Перечисление 10-12  реализация firstRectForRange:

- (CGRect)firstRectForRange:(UITextRange *)range {
    IndexedRange *r = (IndexedRange *)range;
    CGRect rect = [_textView firstRectForNSRange:r.range];
    return [self convertRect:rect fromView:_textView];
}

Встроенное текстовое представление в этом случае выполняет львиную долю работы. Используя Базовые текстовые функции, это вычисляет прямоугольник, включающий диапазон текста и возвращающий его, как показано в Перечислении 10-13.

Перечисление 10-13  , Отображающее текст, располагается к включению прямоугольника

- (CGRect)firstRectForNSRange:(NSRange)range; {
    int index = range.location;
    NSArray *lines = (NSArray *) CTFrameGetLines(_frame);
    for (int i = 0; i < [lines count]; i++) {
        CTLineRef line = (CTLineRef) [lines objectAtIndex:i];
        CFRange lineRange = CTLineGetStringRange(line);
        int localIndex = index - lineRange.location;
        if (localIndex >= 0 && localIndex < lineRange.length) {
            int finalIndex = MIN(lineRange.location + lineRange.length,
                range.location + range.length);
            CGFloat xStart = CTLineGetOffsetForStringIndex(line, index, NULL);
            CGFloat xEnd = CTLineGetOffsetForStringIndex(line, finalIndex, NULL);
            CGPoint origin;
            CTFrameGetLineOrigins(_frame, CFRangeMake(i, 0), &origin);
            CGFloat ascent, descent;
            CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
 
            return CGRectMake(xStart, origin.y - descent, xEnd - xStart, ascent + descent);
        }
    }
    return CGRectNull;
}

Для caretRectForPosition:, подход Вы взятие несколько отличался бы. Сродство выбора (selectionAffinity) фактор для рассмотрения; что еще более важно имейте в виду, что высота и ширина прямоугольника каре могут отличаться от ограничительного прямоугольника, возвращенного из firstRectForRange:.

Тестирование хита

Другая область, где система ввода текста просит, чтобы текстовое представление отобразилось между дисплеем текста и хранением текста, поражена, тестируя. Учитывая точку в текстовом представлении (система ввода текста спрашивает), каковы соответствующая текстовая позиция или текстовый диапазон? UITextInput методы это требует эту информацию, closestPositionToPoint:, closestPositionToPoint:withinRange:, и characterRangeAtPoint:. Перечисление 10-14 иллюстрирует как EditableCoreTextView реализует первый из этих методов.

Перечисление 10-14  реализация closestPositionToPoint:

- (UITextPosition *)closestPositionToPoint:(CGPoint)point {
    NSInteger index = [_textView closestIndexToPoint:point];
    return [IndexedPosition positionWithIndex:(NSUInteger)index];
}

Здесь, как с методами, возвращающими прямоугольники для текстовых диапазонов или текстовых позиций, EditableCoreTextView вызывает метод его встроенного представления, что текст Ядра использования для вычисления индекса символа, соответствующего точке. Перечисление 10-15 иллюстрирует, как встроенное представление выполняет это.

Перечисление 10-15  , Отображающее точку на индекс символа

- (NSInteger)closestIndexToPoint:(CGPoint)point {
    NSArray *lines = (NSArray *) CTFrameGetLines(_frame);
    CGPoint origins[lines.count];
    CTFrameGetLineOrigins(_frame, CFRangeMake(0, lines.count), origins);
 
    for (int i = 0; i < lines.count; i++) {
        if (point.y > origins[i].y) {
            CTLineRef line = (CTLineRef) [lines objectAtIndex:i];
            return CTLineGetStringIndexForPosition(line, point);
        }
    }
    return  _text.length;
}

Информирование делегата ввода текста изменений

Когда существует изменение в тексте или изменение в выборе, не инициирующемся системой ввода текста, необходимо сообщить делегату ввода текста путем отправки ему надлежащего метода «-изменения». После внесения изменения отправьте делегату соответствующий метод «-изменения».

Делегат ввода текста является предоставленным системой объектом, принимающим UITextInputDelegate протокол. Если класс, принимающий UITextInput протокол определяет inputDelegate свойство, система ввода текста автоматически присваивает объект делегата этому свойству во время выполнения.

Перечисление 10-16 показывает метод действия, вызывающийся, когда пользователь касается в текстовом представлении. Если представление касается, но это не первый респондент, текстовое представление делает себя первым респондентом и запускает сеанс редактирования. Если представление впоследствии касается, текстовое представление отправляет a selectionWillChange: обменивайтесь сообщениями делегату ввода текста. Это тогда очищает любой отмеченный текстовый диапазон и сбрасывает выбранный текстовый диапазон так, чтобы каре было в точке в тексте, где произошел коснувшийся. После этого это вызывает selectionDidChange:.

Перечисление 10-16  , Отправляющее сообщения делегату ввода текста

- (void)tap:(UITapGestureRecognizer *)tap
{
    if (![self isFirstResponder]) {
        _textView.editing = YES;
        [self becomeFirstResponder];
    } else {
        [self.inputDelegate selectionWillChange:self];
 
        NSInteger index = [_textView closestIndexToPoint:[tap locationInView:_textView]];
        _textView.markedTextRange = NSMakeRange(NSNotFound, 0);
        _textView.selectedTextRange = NSMakeRange(index, 0);
 
        [self.inputDelegate selectionDidChange:self];
    }
}

Проверка правописания и Word Completion

С экземпляром UITextChecker класс, можно проверить написание документа или выдвинуть предположения для завершения частично вводимых слов. Когда проверка правописания документ, a UITextChecker поиски объектов документ при указанном смещении. Когда это обнаруживает слово с ошибками, это может также возвратить массив возможных корректных написаний, оцениваемых в порядке, который они должны быть представлены пользователю (т.е. наиболее вероятное заменяющее слово на первом месте). Вы обычно используете единственный экземпляр UITextChecker на документ, несмотря на то, что можно использовать единственный экземпляр для проверения правописание связанных частей текста, если Вы хотите совместно использовать проигнорированные слова и другое состояние.

Метод, который Вы используете для проверки документа для слов с ошибками, rangeOfMisspelledWordInString:range:startingAt:wrap:language:; метод, используемый для получения списка возможных заменяющих слов, guessesForWordRange:inString:language:. Вы вызываете эти методы в данном порядке. Для проверки всего документа Вы вызываете эти два метода в цикле, сбрасывая начальное смещение к символу после исправленного слова в каждом цикле через цикл, как показано в Перечислении 10-17.

  Проверка правописания перечисления 10-17 документ

- (IBAction)spellCheckDocument:(id)sender {
    NSInteger currentOffset = 0;
    NSRange currentRange = NSMakeRange(0, 0);
    NSString *theText = textView.text;
    NSRange stringRange = NSMakeRange(0, theText.length-1);
    NSArray *guesses;
    BOOL done = NO;
 
    NSString *theLanguage = [[UITextChecker availableLanguages] objectAtIndex:0];
    if (!theLanguage)
        theLanguage = @"en_US";
 
    while (!done) {
        currentRange = [textChecker rangeOfMisspelledWordInString:theText range:stringRange
            startingAt:currentOffset wrap:NO language:theLanguage];
        if (currentRange.location == NSNotFound) {
            done = YES;
            continue;
        }
        guesses = [textChecker guessesForWordRange:currentRange inString:theText
            language:theLanguage];
        NSLog(@"---------------------------------------------");
        NSLog(@"Word misspelled is %@", [theText substringWithRange:currentRange]);
        NSLog(@"Possible replacements are %@", guesses);
        NSLog(@" ");
        currentOffset = currentOffset + (currentRange.length-1);
    }
}

UITextChecker класс включает методы для сообщения текстового средства проверки проигнорировать или изучить слова. Вместо того, чтобы просто регистрировать слова с ошибками и их возможные замены, как метод в Перечислении 10-17 делает, необходимо вывести на экран некоторый пользовательский интерфейс, позволяющий пользователям выбирать корректные написания, говорить текстовому средству проверки игнорировать или изучать слово и продолжаться к следующему слову, не внося изменений. Один возможный подход для приложения для iPad должен был бы использовать представление легкой сдобы, перечисляющее предположения в табличном представлении и включающее кнопки, такие как Замена, Изучите, Проигнорируйте и т.д.

Можно также использовать UITextChecker получить завершения для частично вводимых слов и вывести на экран завершения в табличном представлении в представлении легкой сдобы. Для этой задачи Вы вызываете completionsForPartialWordRange:inString:language: метод, передающий в диапазоне в данной строке для проверки. Этот метод возвращает массив возможных слов, завершающих частично вводимое слово. Перечисление 10-18 показывает, как Вы могли бы вызвать этот метод и вывести на экран табличное представление, перечисляющее завершения в представлении легкой сдобы.

Перечисление 10-18  , Представляющее список завершений слова для текущей частичной строки

- (IBAction)completeCurrentWord:(id)sender {
 
    self.completionRange = [self computeCompletionRange];
    // The UITextChecker object is cached in an instance variable
    NSArray *possibleCompletions = [textChecker completionsForPartialWordRange:self.completionRange
        inString:self.textStore language:@"en"];
 
    CGSize popOverSize = CGSizeMake(150.0, 400.0);
    completionList = [[CompletionListController alloc] initWithStyle:UITableViewStylePlain];
    completionList.resultsList = possibleCompletions;
    completionListPopover = [[UIPopoverController alloc] initWithContentViewController:completionList];
    completionListPopover.popoverContentSize = popOverSize;
    completionListPopover.delegate = self;
    // rectForPartialWordRange: is a custom method
    CGRect pRect = [self rectForPartialWordRange:self.completionRange];
    [completionListPopover presentPopoverFromRect:pRect inView:self
        permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}