Начиная с iOS 8, ваши приложения могут расширять пользовательские функции и контент за пределы вашего приложения и делать его доступным для пользователей, когда они используют другие приложения или операционную систему. Одним из способов расширения операционной системы является создание собственной клавиатуры.
В этом уроке я покажу вам, как создать свою собственную клавиатуру с помощью Swift и новых API расширений приложений. Прежде чем мы это сделаем, мы рассмотрим, что может делать расширение для клавиатуры, что оно не может делать и что нужно получить для одобрения в App Store.
1. Обзор
Пользовательская клавиатура заменяет системную клавиатуру для пользователей, которым нужны такие возможности, как новый метод ввода текста или возможность ввода текста на языке, который не поддерживается операционной системой.
Основная функция пользовательской клавиатуры проста, реагирует на нажатия, жесты или другие события ввода и предоставляет текст в виде неназначенного объекта NSString
в точке вставки текста текущего объекта ввода текста.
После того, как пользователь выбирает клавиатуру, она остается стандартной по умолчанию при каждом открытии приложения. По этой причине клавиатура должна позволять пользователю переключаться на другую клавиатуру.
Для каждой настраиваемой клавиатуры есть две основы разработки:
Доверять. Ваша пользовательская клавиатура дает вам доступ к тому, что печатает пользователь, поэтому доверие между вами и вашим пользователем является существенным.
Клавиша «Следующая клавиатура». Возможность, позволяющая пользователю переключаться на другую клавиатуру, является частью пользовательского интерфейса клавиатуры; Вы должны предоставить один на клавиатуре. — Руководство по программированию расширения приложения
Если вам нужно всего лишь добавить несколько кнопок на системную клавиатуру, вы должны посмотреть в пользовательских представлениях для ввода данных .
2. Требования и ограничения
Что не может сделать пользовательская клавиатура
Существуют определенные объекты ввода текста, которые ваша пользовательская клавиатура не может набирать. К ним относятся защищенные текстовые поля для ввода паролей и объекты телефонной панели, например поля телефонных номеров в приложении « Контакты» .
Ваша пользовательская клавиатура не имеет доступа к иерархии представлений ввода, она не может управлять курсором и не может выбирать текст. Кроме того, пользовательская клавиатура не может отображать ничего выше верхнего ряда. Системная клавиатура не ограничена этими ограничениями. Например, он показывает расширение, когда вы нажимаете клавишу, чтобы показать пользователю, какая клавиша была нажата.
Песочница
По умолчанию клавиатура не имеет доступа к сети и не может обмениваться файлами со своим приложением. Чтобы включить эти возможности, установите значение ключа RequestsOpenAccess
в файле Info.plist
на YES
. Это расширяет «песочницу» клавиатуры, как описано в Руководстве по программированию расширений приложений Apple.
Если вы запрашиваете открытый доступ, ваша клавиатура приобретает следующие возможности, каждая с сопутствующей ответственностью:
- доступ к службам определения местоположения и базе данных адресной книги, каждая из которых требует разрешения пользователя при первом доступе
- возможность использовать общий контейнер с приложением, содержащим клавиатуру, который включает такие функции, как предоставление пользовательского интерфейса управления лексикой в содержащем приложении
- возможность отправлять нажатия клавиш и другие входные события для обработки на стороне сервера
- доступ к iCloud, который вы можете использовать, например, для обеспечения актуальности настроек клавиатуры и вашей пользовательской лексики автозамены на всех устройствах, принадлежащих пользователю
- доступ к Game Center и покупка из приложения через содержащее приложение
- возможность работы с управляемыми приложениями, если вы разрабатываете клавиатуру для поддержки управления мобильными устройствами (MDM)
Обязательно прочитайте документ Apple Designing for User Trust , в котором описана ваша ответственность за соблюдение и защиту пользовательских данных в случае, если вы запрашиваете открытый доступ.
3. Как это работает
В самой простой форме у нас есть приложение, которое содержит расширение клавиатуры и UIInputViewController
который управляет клавиатурой и реагирует на пользовательские события.
Шаблон Custom Keyboard содержит подкласс UIInputViewController
, который является основным контроллером представления вашей клавиатуры. Давайте посмотрим на интерфейс, чтобы понять, как он работает.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
class UIInputViewController : UIViewController, UITextInputDelegate, NSObjectProtocol {
var inputView: UIInputView!
var textDocumentProxy: NSObject!
func dismissKeyboard()
func advanceToNextInputMode()
// This will not provide a complete repository of a language’s vocabulary.
// It is solely intended to supplement existing lexicons.
func requestSupplementaryLexiconWithCompletion(completionHandler: ((UILexicon!) -> Void)!)
}
|
-
inputView
— это вид, используемый для клавиатуры, он совпадает со свойствомview
- метод
dismissKeyboard
может быть вызван для отклонения клавиатуры -
advanceToNextInputMode
используется для переключения между клавиатурами -
textDocumentProxy
— это объект, который вы будете использовать для взаимодействия с текущим вводом текста
1
2
3
|
self.textDocumentProxy.insertText(«Tuts+») // inserts the string «Tuts+» at the insertion point
self.textDocumentProxy.deleteBackward() // Deletes the character to the left of the insertion point
|
-
UIInputViewController
соответствует протоколуUITextInputDelegate
, уведомляя вас об изменении текста или выделения текста с помощью событийselectionWillChange
,selectionDidChange
,textWillChange
иtextDidChange
4. Создание клавиатуры калькулятора
Давайте создадим пользовательскую клавиатуру, чтобы сделать все это немного более осязаемым. Мы сделаем простую клавиатуру, которая может обрабатывать числовой ввод и простые операции. Мы собираемся использовать файл XIB для пользовательского интерфейса клавиатуры.
Шаг 1: Создайте новый проект
Откройте Xcode 6, создайте новое приложение Single View и выберите Swift в качестве языка программирования. Назовите это CalculatorKeyboard .
Шаг 2: Добавить текстовое поле
Откройте Main.storyboard
и перетащите текстовое поле из библиотеки объектов . Мы будем использовать это для проверки клавиатуры позже. Отцентрируйте текстовое поле и добавьте необходимые ограничения макета, как показано ниже.
Если вы вызовите textField.becomeFirstResponder()
в viewDidLoad
клавиатура откроется при запуске приложения.
Шаг 3: Добавьте расширение клавиатуры
Выберите файл проекта в Навигаторе проектов и добавьте новую цель, нажав кнопку «плюс» внизу.
Выберите расширение приложения слева, выберите шаблон пользовательской клавиатуры и назовите его « Калькулятор» .
Это создаст новую группу с именем Calculator , содержащую два файла KeyboardViewController.swift и Info.plist .
Шаг 4: Очистка
Откройте KeyboardViewController.swift . Клавиатура шаблона имеет одну кнопку, позволяющую пользователю переключаться между клавиатурами. Удалите код в методе viewDidLoad
.
Шаг 5: Создание пользовательского интерфейса
Щелкните правой кнопкой мыши группу « Калькулятор » и выберите « Новый файл» . Выберите раздел « Интерфейс пользователя » слева, выберите шаблон « Вид» и назовите его « Калькулятор» . Это должно создать файл с именем Calculator.xib .
Откройте файл XIB и в инспекторе атрибутов справа установите для размера значение « Свободная форма», а для строки состояния — « Нет» .
В инспекторе размера установите ширину вида 320
а высоту 160
.
Перетащите кнопку из библиотеки объектов в представление. В инспекторе атрибутов установите заголовок равным 1 . В инспекторе размера установите ширину и высоту кнопки равными 30
. Переместите кнопку в верхний правый угол представления, пока она не выровняется с полями.
Скопируйте кнопку, нажав и перетащив ее, одновременно нажимая клавишу параметров. Расположите вторую кнопку под первой.
Выберите кнопки, нажав Command-A и скопируйте кнопки. Расположите новые кнопки под первой и второй кнопкой.
Повторите процесс, чтобы создать еще один столбец кнопок, пока у вас не будет четырех столбцов кнопок.
Затем выберите столбец слева и сделайте копию, которая выравнивается по левой границе вида.
Установите ширину кнопок до 140
точек. Замените верхнюю левую кнопку с меткой, размер которой совпадает с размером кнопки. Переименуйте кнопки, как на скриншоте ниже.
Придайте виду синий цвет фона и установите белый цвет фона кнопок с непрозрачностью 15%. А для метки дисплея сделайте его черным с непрозрачностью 15%. Установите размер текста в 18
точек для каждого объекта пользовательского интерфейса и установите цвет текста на белый. Теперь пользовательский интерфейс должен выглядеть так:
Шаг 6: Загрузка пользовательского интерфейса
Сначала нам нужно создать свойство для хранения пользовательского интерфейса.
1
2
3
4
5
|
class KeyboardViewController: UIInputViewController {
var calculatorView: UIView!
…
}
|
Создайте метод с именем loadInterface
и вызовите его в методе viewDidLoad
KeyboardViewController
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
class KeyboardViewController: UIInputViewController {
…
override func viewDidLoad() {
super.viewDidLoad()
loadInterface()
}
func loadInterface() {
// load the nib file
var calculatorNib = UINib(nibName: «Calculator», bundle: nil)
// instantiate the view
calculatorView = calculatorNib.instantiateWithOwner(self, options: nil)[0] as UIView
// add the interface to the main view
view.addSubview(calculatorView)
// copy the background color
view.backgroundColor = calculatorView.backgroundColor
}
…
}
|
Шаг 7: Тестирование клавиатуры
На этом этапе вы сможете протестировать новую клавиатуру. Выбрав схему CalculatorKeyboard , соберите и запустите приложение на своем устройстве. Это добавит новую клавиатуру на ваше устройство. Однако, прежде чем вы сможете использовать его, вам сначала нужно установить его.
Перейдите в « Настройки» > « Основные» > « Клавиатура» > « Клавиатуры» и выберите « Добавить новую клавиатуру» . Там вы найдете клавиатуру калькулятора в списке сторонних клавиатур. Выберите и установите клавиатуру. В следующий раз, когда вы откроете клавиатуру, вы сможете увидеть новую клавиатуру, нажав кнопку следующей клавиатуры.
Если вы используете симулятор iOS, пользовательская клавиатура может не работать внутри вашего приложения. Чтобы увидеть клавиатуру, нажмите домой и откройте Spotlight.
Шаг 8: Следующая клавиатура
Создайте свойство для следующей кнопки KeyboardViewController
классе KeyboardViewController
.
1
2
3
4
5
6
|
class KeyboardViewController: UIInputViewController {
@IBOutlet var nextKeyboardButton: UIButton!
…
}
|
Откройте Calculator.xib , выберите «Владелец файла» , а в инспекторе удостоверений измените его класс на KeyboardViewController
.
Щелкните правой кнопкой мыши на кнопке « Следующая клавиатура» и подключите источник ссылки к владельцу файла .
В методе loadInterface
мы добавляем действие к кнопке nextKeyboard
, как показано ниже.
01
02
03
04
05
06
07
08
09
10
11
|
class KeyboardViewController: UIInputViewController {
…
func loadInterface() {
…
// This will make the button call advanceToNextInputMode() when tapped
nextKeyboardButton.addTarget(self, action: «advanceToNextInputMode», forControlEvents: .TouchUpInside)
}
}
|
Шаг 9: Отображение номера
Создайте свойство для отображения и подключите выходную ссылку в Интерфейсном Разработчике.
1
2
3
4
5
6
|
class KeyboardViewController: UIInputViewController {
@IBOutlet var display: UILabel!
…
}
|
Создайте метод с именем clearDisplay
и вызовите его в методе viewDidLoad
после вызова loadInterface
. Дисплей должен показывать 0 при открытии клавиатуры.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
class KeyboardViewController: UIInputViewController {
…
override func viewDidLoad() {
super.viewDidLoad()
loadInterface()
clearDisplay()
}
…
@IBAction func clearDisplay() {
display.text = «0»
}
}
|
Подсоедините событие касания кнопки C к событию clearDisplay
в Интерфейсном clearDisplay
.
Шаг 10: Ввод числа
Время обрабатывать числовой ввод. Когда вы открываете клавиатуру, на дисплее отображается 0 . Если вы нажмете цифровую клавишу, она должна заменить дисплей на этот номер. Создайте свойство с именем shouldClearDisplayBeforeInserting
для реализации этого поведения.
Создайте метод с именем didTapNumber
и подключите его в Интерфейсном didTapNumber
ко всем didTapNumber
кнопкам для события внутренней обработки . Метод использует titleLabel
кнопки, чтобы определить, какое число было нажато.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
class KeyboardViewController: UIInputViewController {
var shouldClearDisplayBeforeInserting = true
…
@IBAction func didTapNumber(number: UIButton) {
if shouldClearDisplayBeforeInserting {
display.text = «»
shouldClearDisplayBeforeInserting = false
}
if var numberAsString = number.titleLabel?.text {
var numberAsNSString = numberAsString as NSString
if var oldDisplay = display?.text!
display.text = «\(oldDisplay)\(numberAsNSString.intValue)»
} else {
display.text = «\(numberAsNSString.intValue)»
}
}
}
}
|
Обновите метод clearDisplay
как показано ниже.
1
2
3
4
5
6
7
8
|
class KeyboardViewController: UIInputViewController {
…
@IBAction func clearDisplay() {
display.text = «0»
shouldClearDisplayBeforeInserting = true
}
}
|
Код клавиатуры находится в другом месте, чем ваше приложение. Из-за этого журналы отладки не видны. Чтобы просмотреть журналы для цели « Калькулятор» , откройте системный журнал из симулятора iOS.
Шаг 11: Точечный ввод
Кнопка для вставки точки должна добавить точку на дисплей, но только если точки еще нет.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
class KeyboardViewController: UIInputViewController {
…
@IBAction func didTapDot() {
if let input = display?.text {
var hasDot = false
for ch in input.unicodeScalars {
if ch == «.»
hasDot = true
break
}
}
if hasDot == false {
display.text = «\(input).»
}
}
}
}
|
Шаг 12: Вставка текста
Кнопка для вставки текста должна добавить отображаемый текст калькулятора к точке вставки. Для этого мы используем свойство textDocumentProxy
как показано ниже.
01
02
03
04
05
06
07
08
09
10
11
|
class KeyboardViewController: UIInputViewController {
…
@IBAction func didTapInsert() {
var proxy = textDocumentProxy as UITextDocumentProxy
if let input = display?.text as String?
proxy.insertText(input)
}
}
}
|
Шаг 13: Обработка операций
Поскольку мы реализуем простую клавиатуру, которая не поддерживает деревья выражений , 1 + 2 * 3
будет равно 9
. Мы собираемся использовать более простую модель, в которой калькулятор имеет слот внутренней памяти, к которому он может применять операции.
Давайте сделаем простой ввод, чтобы понять, как работает алгоритм калькулятора:
- пользователь нажимает
1
, дисплей должен измениться с0
на1
- пользователь нажимает
+
, калькулятор должен помнить, чтобы добавить следующий введенный номер к1
- пользователь нажимает
2
, дисплей должен измениться с1
на2
- пользователь нажимает
*
, дисплей и внутренняя память калькулятора должны измениться на3
, калькулятор должен помнить, чтобы умножить внутреннюю память на следующее введенное число - пользователь нажимает
3
, дисплей должен оставаться3
- пользователь нажимает
=
, калькулятор должен применить последнюю операцию, и дисплей должен измениться на9
Замечания:
- калькулятор должен запомнить следующую операцию для применения
- после ввода числа, если нажата операция или равно, калькулятор должен применить последнюю запомненную операцию
- если пользователь нажимает две или более операций без ввода числа, калькулятор должен запомнить последнюю
- после применения операции дисплей должен обновить результат
- после отображения результата дисплей должен очиститься перед записью другого числа
Для реализации калькулятора нам понадобятся:
- свойство
internalMemory
котором хранится временный результат - свойство, которое хранит
nextOperation
- еще один, чтобы запомнить, следует ли применять
nextOperation
после нажатия операции
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
enum Operation {
case Addition
case Multiplication
case Subtraction
case Division
case None
}
class KeyboardViewController: UIInputViewController {
var internalMemory = 0.0
var nextOperation = Operation.None
var shouldCompute = false
…
}
|
Создайте метод с именем didTapOperation
и подключите его к кнопкам операций, didTapOperation
внутреннее событие в Интерфейсном Разработчике. Метод будет использовать заголовок кнопки, чтобы определить, какая операция была нажата.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
class KeyboardViewController: UIInputViewController {
…
@IBAction func didTapOperation(operation: UIButton) {
if shouldCompute {
computeLastOperation()
}
if var op = operation.titleLabel?.text {
switch op {
case «+»:
nextOperation = Operation.Addition
case «-«:
nextOperation = Operation.Subtraction
case «X»:
nextOperation = Operation.Multiplication
case «%»:
nextOperation = Operation.Division
default:
nextOperation = Operation.None
}
}
}
}
|
Создать и реализовать метод computeLastOperation
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
class KeyboardViewController: UIInputViewController {
…
@IBAction func computeLastOperation() {
// remember not to compute if another operation is pressed without inputing another number first
shouldCompute = false
if var input = display?.text {
var inputAsDouble = (input as NSString).doubleValue
var result = 0.0
// apply the operation
switch nextOperation {
case .Addition:
result = internalMemory + inputAsDouble
case .Subtraction:
result = internalMemory — inputAsDouble
case .Multiplication:
result = internalMemory * inputAsDouble
case .Division:
result = internalMemory / inputAsDouble
default:
result = 0.0
}
nextOperation = Operation.None
var output = «\(result)»
// if the result is an integer don’t show the decimal point
if output.hasSuffix(«.0») {
output = «\(Int(result))»
}
// truncatingg to last five digits
var components = output.componentsSeparatedByString(«.»)
if components.count >= 2 {
var beforePoint = components[0]
var afterPoint = components[1]
if afterPoint.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) > 5 {
let index: String.Index = advance(afterPoint.startIndex, 5)
afterPoint = afterPoint.substringToIndex(index)
}
output = beforePoint + «.»
}
// update the display
display.text = output
// save the result
internalMemory = result
// remember to clear the display before inserting a new number
shouldClearDisplayBeforeInserting = true
}
}
}
|
Обновите метод clearDisplayMethod
как показано ниже. Когда пользователь начинает писать первое число, внутренняя память должна быть установлена на 0
а nextOperation
должна быть добавлена. Таким образом, после того, как пользователь введет первое число и нажмет операцию, калькулятор запомнит введенное число.
01
02
03
04
05
06
07
08
09
10
|
class KeyboardViewController: UIInputViewController {
…
@IBAction func clearDisplay() {
display.text = «0»
internalMemory = 0
nextOperation = Operation.Addition
shouldClearDisplayBeforeInserting = true
}
}
|
Шаг 14: Последние штрихи
Давайте используем атрибут объявления IBInspectable, чтобы добавить угловой радиус для кнопок и отображения. Сначала создайте подкласс UIButton
и UILabel
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
class RoundButton: UIButton {
@IBInspectable var cornerRadius: CGFloat = 0 {
didSet {
layer.cornerRadius = cornerRadius
}
}
}
class RoundLabel: UILabel {
@IBInspectable var cornerRadius: CGFloat = 0 {
didSet {
layer.cornerRadius = cornerRadius
}
}
}
|
В Интерфейсном RoundButton
выберите кнопки и измените их класс на RoundButton
в Инспекторе Идентификации . В инспекторе Атрибутов вы должны увидеть новый атрибут радиуса угла.
Сделайте то же самое для метки дисплея. Ваша клавиатура должна выглядеть следующим образом.
Вывод
Теперь вы должны иметь возможность создать собственную клавиатуру в iOS с помощью API расширений приложения. Помните, что каждая настраиваемая клавиатура должна иметь способ переключения на следующую клавиатуру и что ваша клавиатура не может подключаться к Интернету, получать доступ к службам определения местоположения или общаться с приложением по умолчанию, но вы можете запросить эти возможности.
Система будет использовать клавиатуру по умолчанию для защищенных полей, таких как поля пароля и номера телефона. Не забывайте, что код для пользовательской клавиатуры находится в отдельной цели. Из-за этого журналы отладки не видны. Чтобы увидеть их, откройте системный журнал из iOS Simulator.