Создать клавиатуру для айфона

Разрабатываем хабраклавиатуру под iOS


Зачастую для чтения хабра я использую мобильное приложение Хабрахабр для iPhone и iPad. Оно достаточно удобное для чтения статей, но не очень удобное для написания комментариев, особенно если хочется написать что-нибудь этакое, с использованием тегов форматирования. Неудобно, потому что все теги необходимо набирать вручную, поэтому очень легко ошибиться и, как результат, оставить некрасивый комментарий.

Так у меня появилась идея написать свою клавиатуру, в которой по нажатию на клавишу добавляется открывающийся и закрывающийся тег в текстовое поле. Курсор при этом должен стать прямо между ними, чтобы сразу же приступить к написанию текста. Также необходимо иметь возможность перемещать курсор с помощью жестов свайпа, субъективно это удобней, чем тянуть палец к полю, ожидать появления лупы, перемещать палец и надеяться, что курсор попадет куда надо. И наконец, пора бы уже разобраться с тегами «Сарказм» и «Зануда», которые не поддерживаются парсером хабра. Клавиатура должна иметь специальные клавиши для этих целей, а оформление тегов должно быть конфигурируемым в настройках клавиатуры, чтобы каждый мог указать тот вид, который ему нравится.

С выходом iOS 8 Apple открывает новый API, который позволяет разрабатывать расширения к приложениям. Клавиатура (Custom Keyboard) является одним из представителей таких расширений. О ней и пойдет речь. В статье вы узнаете о том, какие возможности, ограничения и баги предоставляет новый API, как разработать хабраклавиатуру, и как сделать так, чтобы ваша клавиатура появилась в AppStore, а следовательно и на устройствах ваших пользователей.

Возможности и ограничения

Открыв доступ к API для создания сторонних клавиатур, Apple построила узкий мостик между приложениями. С одной стороны каждое приложение по-прежнему находится в своей песочнице, но с другой — введенные данные в одном приложении теперь могут попадать в другое, либо напрямую отправляться на сервер. Такая функциональность является достаточно серьезной с точки зрения безопасности пользовательских данных, поэтому Apple строго определила, что можно делать, а что нельзя. Прежде, чем перейти к детальному описанию, хочу пояснить, что все типы расширений, в том числе и клавиатура, могут быть установлены на мобильное устройство только в составе основного приложения (приложения-контейнера). Например, в последнюю версию приложения Хабрахабр было добавлено расширение в виде виджета в Notification Center.

И так, какие же возможности мы имеем:

  • Сторонняя клавиатура может быть использована практически в любом приложении, установленном на устройстве. Для этого пользователю необходимо собственноручно добавить установленную клавиатуру в настройках устройства. К счастью разработчики приложений могут запретить использование сторонних клавиатур в их приложениях, но об этом позже;
  • Клавиатура может обмениваться данными как с приложением-контейнером, так и с сервером разработчика. Разрешение такого обмена настраивается пользователем, при чем изначально эта возможность отключена;
  • Клавиатура может иметь доступ к сервису геолокации и адресной книги. Для получения доступа небходимо разрешение пользователя как в настройках клавиатуры, так и в настройках соответствующего сервиса;
  • Клавиатура может обращаться к встроенному словарю для отображения вариантов автокоррекции и автодополнения введенного текста. Данные берутся из следующих источников:
    1. Адресная книга устройства (имена и фамилии предоставляются непарно);
    2. Сокращения, указанные пользвателем в настройках смартфона;
    3. Общий словарь.

Это, собственно, все основные возможности. Перейдем к ограничениям:

  • Нельзя унаследоваться от стандартной клавиатуры. То есть взять за основу встроенную клавиатуру и добавить в нее обработку жестов для управления курсором не получится, придется все делать практически с нуля. Более того, стандартную клавиатуру невозможно воссоздать в принципе. Причины описаны в следующих пунктах;
  • Сторонняя клавиатура, как и другие типы расширений, не имеет доступа к микрофону, что делает невозможным поддержку голосового ввода;
  • Стороння клавиатура не может быть использована для ввода скрытого текста ( secureTextEntry = YES ). То есть, если поле предназначено для ввода пароля, то пользователь сможет воспользоваться только стандартной клавиатурой;
  • Кастомная клавиатура не может быть использована для полей с типом UIKeyboardTypePhonePad и UIKeyboardTypeNamePhonePad ;
  • Клавиатура не имеет доступа к выделению текста в поле ввода. То есть поменять выделение без участия пользователя не получится;
  • В отличие от стандартной клавиатуры, в сторонней не получится вылезти за пределы фрейма. То есть нельзя отобразить что-либо выше клавиатуры, как, например, при длительном нажатии на клавиши верхнего ряда стандартной клавиатуры;
  • Разработчики могут запретить использование сторонних клавиатур в их приложениях. Для этого необходимо переопределить метод application:shouldAllowExtensionPointIdentifier: протокола UIApplicationDelegate . Для идентификатора с именем UIApplicationKeyboardExtensionPointIdentifier необходимо возвращать NO . К слову, для iOS 8 это единственный тип расширений, который можно запретить использовать.
Читайте также:  Iphone 3gs год выхода

Полная документация по разработке кастомных клавиатур: Custom Keyboard

Хабраклавиатура

С теорией разобрались, переходим к практике.
Создаем новый проект, выбираем Application, все стандартно.

Далее необходимо добавить новый Target «Custom Keyboard».

В результате Xcode генерирует класс – наследник от UIInputViewController и Info.plist .
Класс UIInputViewController является контроллером клавиатуры. Все взаимодействие с полем ввода происходит через него. Рассмотрим интерфейс класса более подробно.
Основные методы:

  • — (void)dismissKeyboard – позволяет скрыть клавиатуру. Это та возможность, которая отсутствует во всех стандартных клавиатурах в iPhone;
  • — (void)advanceToNextInputMode – выполняет отображение следующей клавиатуры. Список доступных клавиатур определяется пользователем в настройках устройства;
  • — (void)requestSupplementaryLexiconWithCompletion:(void (^)(UILexicon *))completionHandler – предоствляет массив пар строк. Каждая пара состоит из строки, которую может ввести пользователь userInput и строки, которая является автодополнением или автокоррекцией documentText . Например, на моем iPhone этот метод возвращает 151 пару.

Для взаимодействия с полем предоставляется свойство textDocumentProxy . Приведу описание только наиболее важных для разработки методов:

  • — (void)adjustTextPositionByCharacterOffset:(NSInteger)offset – позволяет управлять курсором;
  • — (NSString *)documentContextBeforeInput – возвращает строку до курсора;
  • — (NSString *)documentContextAfterInput – возвращает строку после курсора;
  • — (void)insertText:(NSString *)text – вставляет строку после курсора;
  • — (void)deleteBackward – удаляет один символ перед курсором;
  • — (UIKeyboardAppearance)keyboardAppearance – позволяет определить, какая тема используется: светлая или темная;
  • — (UIKeyboardType)keyboardType – позволяет определить, какой тип клавиатуры требует поле ввода.

Помимо выше описанных методов класс UIInputViewController реализует протокол UITextInputDelegate :

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

  • Первые два метода никогда не вызываются вне зависимости от того, выделяет пользователь текст или нет;
  • Последние два метода вызываются, но объект textInput всегда nil .

Похоже на баг. На Stackoverflow люди пишут, что столкнулись с такой же проблемой, решения нет. Хочу отметить, что выше описанное поведение воспроизводится на релизной версии iOS8.

Второй точкой соприкосновения для разработчика является файл Info.plist . Помимо уже известных полей он содержит группу NSExtension :

В ней указывается тип разрабатываемого расширения, имя класса-контроллера и атрибуты. Обратите внимание на атрибут RequestsOpenAccess . С помощью его система понимает необходим ли вам расширенный доступ: обмен данными с приложением-контейнером или сервером, доступ к геолокации и адресной книге. Если укажете true , то будьте готовы объяснять Apple для чего вам это все нужно.

На этом ознакомление с API завершаем и приступаем к непосредственной разработке.
Для начала определим лэйаут. Я планировал реализовать поддержку портретной и альбомной ориентаций для iPhone и со временем доработать для iPad. Лэйаут для портретной и альбомной ориентаций должен был немного отличаться. Для этих целей отлично подходила новоиспеченная технология Sizes Classes. Почему я пишу в прошедшем времени? Да потому что все планы провалились. Дело в том, что в независимости от ориентации система назначает нам одинаковые Size Classes: wCompact и hCompact, что соответствует альбомной ориентации для iPhone. Скорее всего это связано с тем, что фрейм клавиатуры занимает не весь экран, а только нижнюю половину. В принципе это логичное поведение, и, чтобы обойти эту проблему, можно вручную назначить произвольный Size Class для контроллера. Для этого необходимо воспользоваться методом setOverrideTraitCollection:forChildViewController: . Но не тут-то было, по факту вызов этого метода ни на что не влияет, то есть UITraitCollection дочернего контроллера остается неизменным. Если у кого-либо из вас был положительный опыт использования этого метода, прошу им поделиться. Версию кода с выше описанным поведением я залил в отдельный бранч, если кому-то интересно можете там поковыряться. Пока проблема не решена будем довольствоваться одним лэйаутом для всех ориентаций:

Читайте также:  Как отследить геопозицию айфона с андроида

Для удобства управления курсором добавим разпознование жестов Swipe. В xib добавляем два объекта UISwipeGestureRecognizer , в коде реализуем обработчики событий:

Далее добавляем обработчики для закрытия клавиатуры и перехода к следующей:

Для удаления введенного текста реализуем две возможности:

  1. Удаление последнего символа перед курсором, как в стандартной клавиатуре:
  2. Удаление всего введенного текста вне зависимости от положения курсора. Чтобы избежать случайного удаления текста будем использовать UILongTapGestureRecognizer :

Для достижения цели приходится использовать хак с выполнением кода с задержкой. Дело в том, что API позволяет удалять текст только перед курсором. То есть для того, чтобы удалить весь текст, необходимо сначала переместить курсор в конец строки, но сам процесс перемещения является асинхронным, в то же время я не нашел возможности узнать момент времени, когда этот процесс завершен. Поэтому ставим задержку в 0.1 секунду и считаем, что курсор достиг свой цели.

Остается разобраться с тем, ради чего мы здесь собственно собрались: с вводом тегов форматирования.
Для хранения стандартных тегов, которые поддерживаются хабром, будем использовать JSON файл:

Для тегов «Сарказм» и «Зануда» необходимо создать настройки, чтобы каждый пользователь мог сам установить значения для открывающегося и закрывающегося тегов. Добавляем Settings Bundle:

Переходим в Settings.bundle -> Root.plist и заполняем все необходимые поля. Ниже представлен исходный код настроек и то, что должен увидеть пользователь:

Но в реальности при установке клавиатуры заначения для тегов не отображаются, то есть по факту поля пустые. Эти поля задаются по ключу Default Value . Сначала я подумал, что делаю что-то не так. Но даже, если зайти в настройки и вручную заполнить эти поля, то при выходе из настроек значения не сохраняются. Это баг. С аналогичной проблемой столкнулись и другие пользователи, несколько топиков на Stackoverflow тому подтверждение, то есть проблема не является локальной. Такое ощущение, что разработчики забыли вызвать метод synchronize у объекта NSUserDefaults . Печально, но остается только ждать обновления iOS 8.1 или iOS 8.0.1. Чтобы учесть эту проблему, я использую дефолтные значения в коде, если из настроек загрузить не удалось.

С хранением тегов разобрались, теперь напишем обработчик нажатия клавиш для добавления тегов в поле ввода:

Здесь используется уже описанный ранее хак с задержкой выполнения кода. Связано это с тем же курсором. Когда мы вызываем метод insertText: курсор перемещается не мгновенно, и это необходимо учитывать. Чтобы объяснить, для чего здесь нужно учитывать смещение курсора, приведу пример: допустим мы хотим добавить ссылку на какого-либо Хабраюзера. Для этого необходимо добавить тег и далее вписать имя пользователя между кавычек. Для удобства я сделал так, чтобы курсор автоматически устанавливался в позицию между кавычек. Аналогично и для других тегов. Для этих целей используется выше описанный метод moveTextPositionToInputPointForTag: , который, используя массив строк-меток, определяет позицию, в которую необходимо установить курсор.

Реализацию завершили, выбираем расширение в качестве активной схемы и запускаем. Для удобства отладки рекомендую зайти в «Edit Scheme» и поставить галочку напротив «Debug executable». Это позволит одновременно отлаживать и расширение, и основное приложение:

Для установки клавиатуры необходимо перейти в Настройки -> Основные -> Клавиатура -> Клавиатуры -> Новые клавиатуры…

На скриншоте справа представлен диалог, который отображается, когда пользователь пытается разрешить полный доступ для клавиатуры. По правде сказать, этот текст намекает мне выбрать «Не разрешать».

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

Полная версия исходного кода доступна на GitHub: Habrakeyboard

Источник

Альтернативные клавиатуры для iPhone

На новых версиях iOS менять можно практически все – в том числе клавиатуру. Узнайте о лучших альтернативных клавиатурах из AppStore.

В одной из версий «яблочной» операционной системы (iOS 8) пользователям Apple стала доступна возможность установки кастомной клавиатуры. После выхода данного обновления долго ждать, пока AppStore наполнится тематическими приложениями, поклонникам «купертиновцев» не пришлось – уже сейчас можно выделить десяток и более клавиатур, которые справляются с вводом текста лучше, чем штатная.

Microsoft Swiftkey

Microsoft Swiftkey является одной из самых загружаемых программ данного типа. Здесь есть большое количество возможностей, которые свойственны всем современным мобильным клавиатурам. Например, при желании можно регулярно менять темы и кастомизировать внешний вид приложения.

В настройках можно установить множество раскладок, изменить тему или задать параметры ввода. Swiftkey умеет подстраиваться под каждого пользователя и запоминает его предпочтения при вводе текста. Это помогает автоматически исправлять ошибки на те слова, которые должны были быть написаны на самом деле. Для удобства можно включить функцию написания жестами (стандартный способ и функция «Flow»).

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

  • Большое количество функций.
  • Детальная настройки раскладки.
  • Статистика ввода.
  • Автоисправление и прогнозирования не только слов, но и Emoji.
  • Более 100 тем на любой вкус.
  • Система управления и ввода жестами.

Gboard

Gboard – не менее популярное приложение от разработчика Google для замены стандартной «яблочной» клавиатуры. Здесь есть поддержка обмена GIF-изображениями, Emoji (графическими и текстовыми), а также фирменными стикерами. А если же этого стандартного набора будет недостаточно, вы сможете самостоятельно найти подходящую GIF или Emoji для более точной передачи своих эмоций.

Самые часто используемые картинки и анимации будут сохраняться в отдельной вкладке, чтобы вы могли быстрее получать к ним доступ. Кроме того, для поиска нужной информации теперь даже не обязательно запускать браузер. В Gboard есть встроенный поисковик, который позволяет искать какие-либо новости (например, результаты спортивных событий, прогноз погоды, данные о работе магазинов, ресторанов и пр.) и делиться ими в два клика.

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

  • Быстрый поиск Emoji и GIF-картинок для любой ситуации.
  • Интеграция клавиатуры с Google для моментального поиска.
  • Непрерывный ввод жестами.
  • Защита личных данных при печатании.
  • Приятный дизайн и около 100 красочных тем.

Grammarly

Grammarly – интересная и необычная клавиатура от разработчика крупнейшего сервиса проверки грамматики, которая во многом похожа по дизайну на предыдущую Gboard, но имеет одно весомое преимущество.

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

Это может быть полезно не только при общении на английском языке, но и при изучении языка. С Grammarly вы будете писать более грамотно. Как и у обычных клавиатур, здесь есть поддержка Emoji, возможность выбрать тему и настроить раскладку. В дополнение мы получаем целый раздел с грамматическими настройками, где вы можете открыть для себя более десятка полезных функций.

  • Исправление любых видов ошибок: орфографических, пунктуационных, грамматических, речевых.
  • Светлая и темная темы.
  • Автоматический подбор более подходящих по контексту слов-синонимов и даже фраз.
  • Анализ написанного вами текста по нескольким критериям.
  • Интуитивно понятный интерфейс.

Источник

Читайте также:  Имя пользователя вай фай айфон
Оцените статью