1. Code
  2. Coding Fundamentals
  3. Tools

Создание пользовательской клавиатуры на Android

Большинство устройств Android не имеют клавиатуры. Вместо этого они полагаются на виртуальную или экранную клавиатуру для ввода текста. Если вы используете персонализацию Android, то знание о создании пользовательской, приятной клавиатуры может вывести ваше хобби на совершенно новый уровень.
Scroll to top

Russian (Pусский) translation by Alex Grigorovich (you can also view the original English article)

Final product imageFinal product imageFinal product image
What You'll Be Creating

Большинство устройств Android не имеют  клавиатуры. Вместо этого они полагаются на виртуальную или экранную клавиатуру для ввода текста. Если вы используете персонализацию Android, то знание о создании пользовательской, приятной клавиатуры может вывести ваше хобби на совершенно новый уровень.

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

В этом уроке вы узнаете, как создать полноценную функциональную клавиатуру, которая может служить для вас на вашем устройстве Android по умолчанию.

1. Предпосылки

Вам понадобится комплект Eclipse ADT Bundle. Вы можете загрузить его с веб-сайта разработчика Android.

2. Создать новый проект

Запустите программу Eclipse и создайте новое приложение для Android. Назовите это приложение SimpleKeyboard. Убедитесь, что вы выбрали уникальное имя пакета. Установите минимально необходимый SDK на значение Android 2.2 и установите целевой SDK на значение Android 4.4

Это приложение не будет иметь никаких действий, поэтому снимите флажок с Создать мероприятие  и нажмите Готово.

3. Отредактируйте манифест

Экранная клавиатура рассматривается как Input Method Editor (IME) для операционной системы Android. IME объявляется как Service в AndroidManifest.xml, который использует разрешение BIND_INPUT_METHOD и отвечает за android.view.InputMethod.

Добавьте следующие строки в тег application файла манифеста:

1
<service android:name=".SimpleIME"
2
    android:label="@string/simple_ime"
3
    android:permission="android.permission.BIND_INPUT_METHOD"
4
    >
5
    <meta-data android:name="android.view.im" android:resource="@xml/method"/>
6
    <intent-filter>
7
        <action android:name="android.view.InputMethod" />
8
    </intent-filter>            
9
</service>

4. Создайте метод.

Тег service в файле манифеста содержит meta-data, который ссылается на файл XML с именем method.xml. Без этого файла операционная система Android не признает наш Service в качестве действительной IME-службы. Файл содержит сведения о методе ввода и его подтипах. Для перевода нашей клавиатуры на другой язык мы выбираем  один подтип en_US. Создайте каталог res/xml, если его нет, и добавьте к нему файл method.xml. Содержимое файла должно быть следующим:

1
<?xml version="1.0" encoding="utf-8"?>
2
<input-method xmlns:android="https://schemas.android.com/apk/res/android"> 
3
    <subtype
4
        android:label="@string/subtype_en_US"  	
5
		android:imeSubtypeLocale="en_US"
6
		android:imeSubtypeMode="keyboard" />
7
</input-method>

5. Редактирование строк.xml

Строки, используемые этим приложением, определены в файле theres/values/strings.xml. Нам понадобятся следующие три строки:

  • имя приложения
  • ярлык IME
  • ярлык подтипа IME

Обновите файл strings.xml, чтобы он имел следующее содержимое:

1
<resources>
2
    <string name="app_name">SimpleKeyboard</string>
3
    <string name="simple_ime">Simple IME</string>
4
    <string name="subtype_en_US">English (US)</string>
5
</resources>

6. Определите макет клавиатуры

Макет нашей клавиатуры содержит только KeyboardView. Атрибут layout_alignParentBottom имеет значение true, чтобы клавиатура отображалась в нижней части экрана.

Создайте файл с именем res/layout/keyboard.xml и замените его содержимое следующим текстом:

1
<?xml version="1.0" encoding="UTF-8"?>
2
<android.inputmethodservice.KeyboardView 
3
    xmlns:android="http://schemas.android.com/apk/res/android"
4
    android:id="@+id/keyboard"
5
    android:layout_width="match_parent"
6
    android:layout_height="wrap_content"
7
    android:layout_alignParentBottom="true"
8
    android:keyPreviewLayout ="@layout/preview"
9
/>

KeyPreviewLayout - это макет недолговечного всплывающего окна, которое появляется при каждом нажатии клавиши на клавиатуре. Он содержит единственный TextView. Создайте файл res/layout/preview.xml и добавьте к нему следующее:

1
<?xml version="1.0" encoding="utf-8"?>
2
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
3
    android:layout_width="match_parent"
4
    android:layout_height="match_parent"
5
    android:gravity="center"
6
    android:background="#ffff00"    
7
    android:textStyle="bold"
8
    android:textSize="30sp"
9
    >    
10
</TextView>

6. Определите клавиши клавиатуры

Детали клавиш клавиатуры и их позиции указаны в файле XML. Каждый ключ имеет следующие атрибуты:

  • keyLabel: этот атрибут содержит текст, отображаемый на клавише.
  • codes: Этот атрибут содержит значения unicode символов, которые представляет ключ.

Например, чтобы определить ключ для буквы A, атрибут codes должен иметь значение 97, а атрибут keyLabel должен быть установлен в A.

Если с ключом связано несколько кодов, тогда символ, который представляет собой ключ, будет зависеть от количества нажатий, которые получает ключ. Например, если ключ имеет коды 63, 33 и 58:

  • одно нажатие на клавишу приводит к символу «?»
  • два быстрых нажатия приводят к символу «!»
  • три  отображают символ «:»

Ключ может также иметь несколько необязательных атрибутов:

  • keyEdgeFlags: этот атрибут может принимать значение left или right. Этот атрибут обычно добавляется к крайним левым и правым клавишам в строке.
  • keyWidth: этот атрибут определяет ширину клавиши. Обычно это определяется в виде процентного значения.
  • isRepeatable: если для этого атрибута установлено значение true, длительное нажатие клавиши будет повторять действие клавиши несколько раз. Обычно значение true установлено для клавиш удаления и пробела.

Клавиши клавиатуры сгруппированы в виде строк. Рекомендуется ограничить количество клавиш в строке до десяти, причем каждая клавиша имеет ширину, равную 10% от клавиатуры. В этом уроке высота клавиш установлена в 60dp. Это значение можно отрегулировать, но значения менее 48dp не рекомендуются. У нашей клавиатуры будет пять рядов ключей.

Теперь мы можем идти вперед и разрабатывать клавиатуру. Создайте новый файл с именем res/xml/qwerty.xml и замените его содержимое следующим текстом:

1
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
2
    android:keyWidth="10%p"
3
	android:horizontalGap="0px"
4
	android:verticalGap="0px"	
5
	android:keyHeight="60dp"
6
>
7
	<Row>
8
		<Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"/>
9
		<Key android:codes="50" android:keyLabel="2"/>
10
		<Key android:codes="51" android:keyLabel="3"/>
11
		<Key android:codes="52" android:keyLabel="4"/>
12
		<Key android:codes="53" android:keyLabel="5"/>
13
		<Key android:codes="54" android:keyLabel="6"/>
14
		<Key android:codes="55" android:keyLabel="7"/>
15
		<Key android:codes="56" android:keyLabel="8"/>
16
		<Key android:codes="57" android:keyLabel="9"/>
17
		<Key android:codes="48" android:keyLabel="0" android:keyEdgeFlags="right"/>
18
	</Row>
19
	<Row>
20
		<Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/>
21
		<Key android:codes="119" android:keyLabel="w"/>
22
		<Key android:codes="101" android:keyLabel="e"/>
23
		<Key android:codes="114" android:keyLabel="r"/>
24
		<Key android:codes="116" android:keyLabel="t"/>
25
		<Key android:codes="121" android:keyLabel="y"/>
26
		<Key android:codes="117" android:keyLabel="u"/>
27
		<Key android:codes="105" android:keyLabel="i"/>
28
		<Key android:codes="111" android:keyLabel="o"/>
29
		<Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/>
30
	</Row>
31
	<Row>
32
		<Key android:codes="97" android:keyLabel="a" android:keyEdgeFlags="left"/>
33
		<Key android:codes="115" android:keyLabel="s"/>
34
		<Key android:codes="100" android:keyLabel="d"/>
35
		<Key android:codes="102" android:keyLabel="f"/>
36
		<Key android:codes="103" android:keyLabel="g"/>
37
		<Key android:codes="104" android:keyLabel="h"/>
38
		<Key android:codes="106" android:keyLabel="j"/>
39
		<Key android:codes="107" android:keyLabel="k"/>		
40
		<Key android:codes="108" android:keyLabel="l"/>
41
		<Key android:codes="35,64" android:keyLabel="\# \@" android:keyEdgeFlags="right"/>
42
	</Row>
43
	<Row>
44
	    <Key android:codes="-1" android:keyLabel="CAPS" android:keyEdgeFlags="left"/>
45
		<Key android:codes="122" android:keyLabel="z"/>
46
		<Key android:codes="120" android:keyLabel="x"/>
47
		<Key android:codes="99" android:keyLabel="c"/>
48
		<Key android:codes="118" android:keyLabel="v"/>
49
		<Key android:codes="98" android:keyLabel="b"/>
50
		<Key android:codes="110" android:keyLabel="n"/>
51
		<Key android:codes="109" android:keyLabel="m"/>
52
		<Key android:codes="46" android:keyLabel="."/>
53
		<Key android:codes="63,33,58" android:keyLabel="\? ! :" android:keyEdgeFlags="right"/>	
54
	</Row>
55
	<Row android:rowEdgeFlags="bottom">
56
	    <Key android:codes="44" android:keyLabel="," android:keyWidth="10%p"  android:keyEdgeFlags="left"/>	
57
		<Key android:codes="47" android:keyLabel="/" android:keyWidth="10%p" />
58
		<Key android:codes="32" android:keyLabel="SPACE" android:keyWidth="40%p" android:isRepeatable="true"/>		
59
		<Key android:codes="-5" android:keyLabel="DEL" android:keyWidth="20%p" android:isRepeatable="true"/>
60
		<Key android:codes="-4" android:keyLabel="DONE" android:keyWidth="20%p" android:keyEdgeFlags="right"/>
61
	</Row>	
62
</Keyboard>

Возможно, вы заметили, что некоторые ключи имеют отрицательные значения в атрибуте codes. Отрицательные значения равны предопределенным константам для класса Keyboard. Например, значение -5 равно значению Keyboard.KEYCODE_DELETE.

7. Создание класса Service

Создайте новый класс Java и назовите его SimpleIME.java. InputMethodService и реализовать интерфейс OnKeyboardActionListener. Интерфейс OnKeyboardActionListener содержит методы, вызываемые при касании или нажатии клавиш экранной клавиатуры.

Класс SimpleIME должен иметь три переменные-члена:

  • KeyboardView, ссылающийся на представление, определенное в макете
  • Экземпляр Keyboard, который назначен для KeyboardView
  • boolean, сообщает нам  включен ли caps lock

После объявления этих переменных и добавления методов интерфейса OnKeyboardActionListener класс SimpleIMEдолжен выглядеть следующим образом:

1
public class SimpleIME extends InputMethodService
2
    implements OnKeyboardActionListener{
3
	
4
	private KeyboardView kv;
5
	private Keyboard keyboard;
6
	
7
	private boolean caps = false;
8
9
	@Override
10
	public void onKey(int primaryCode, int[] keyCodes) {		
11
12
	}
13
14
	@Override
15
	public void onPress(int primaryCode) {
16
	}
17
18
	@Override
19
	public void onRelease(int primaryCode) { 			
20
	}
21
22
	@Override
23
	public void onText(CharSequence text) {		
24
	}
25
26
	@Override
27
	public void swipeDown() {	
28
	}
29
30
	@Override
31
	public void swipeLeft() {
32
	}
33
34
	@Override
35
	public void swipeRight() {
36
	}
37
38
	@Override
39
	public void swipeUp() {
40
	}
41
}

Когда клавиатура создана, вызывается метод onCreateInputViewmethod. Здесь могут быть инициализированы все переменные Service.  Обновите реализацию метода onCreateInputView, как показано ниже:

1
@Override
2
public View onCreateInputView() {
3
	kv = (KeyboardView)getLayoutInflater().inflate(R.layout.keyboard, null);
4
	keyboard = new Keyboard(this, R.xml.qwerty);
5
	kv.setKeyboard(keyboard);
6
	kv.setOnKeyboardActionListener(this);
7
	return kv;
8
}

Затем мы создаем метод, который воспроизводит звук при нажатии клавиши. Мы используем класс AudioManager для воспроизведения звука. Android SDK включает в себя несколько стандартных звуковых эффектов по умолчанию для нажатия клавиш, и они используются в методе playClick.

1
private void playClick(int keyCode){
2
	AudioManager am = (AudioManager)getSystemService(AUDIO_SERVICE);
3
	switch(keyCode){
4
	case 32: 
5
		am.playSoundEffect(AudioManager.FX_KEYPRESS_SPACEBAR);
6
		break;
7
	case Keyboard.KEYCODE_DONE:
8
	case 10: 
9
		am.playSoundEffect(AudioManager.FX_KEYPRESS_RETURN);
10
		break;
11
	case Keyboard.KEYCODE_DELETE:
12
		am.playSoundEffect(AudioManager.FX_KEYPRESS_DELETE);
13
		break;				
14
	default: am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD);
15
	}		
16
}

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

Метод getCurrentInputConnection используется для получения соединения с полем ввода другого приложения. После подключения мы можем использовать следующие методы:

  • commitText для добавления одного или нескольких символов в поле ввода
  • deleteSurroundingText для удаления одного или нескольких символов поля ввода
  • sendKeyEvent для отправки событий, таких как KEYCODE_ENTER, во внешнее приложение

Всякий раз, когда пользователь нажимает клавишу на клавиатуре, onKey вызывается с использованием значения unicode ключа в качестве одного из его параметров. Основываясь на этом значении, клавиатура выполняет одно из следующих действий:

  • В случае, если код следующий - KEYCODE_DELETE, то один символ слева от курсора удаляется с помощью метода deleteSurroundingText.
  • В случае, Если код - KEYCODE_DONE, событие ключа KEYCODE_ENTER запускается.
  • В случае, Если код - KEYCODE_SHIFT, значение caps изменяется, а состояние нажатия клавиатуры обновляется с помощью метода setShifted. При изменении состояния нажатия клавиши должны быть перерисованы, чтобы надписи клавиш были обновлены.  InvalidateAllKeys используется для перерисовки всех ключей.
  • Для всех других кодов код просто преобразуется в символ и отправляется в поле ввода. Если код представляет букву алфавита, а переменная caps имеет значение true, то символ преобразуется в верхний регистр.

Обновите метод onKey, чтобы он выглядел так:

1
@Override
2
public void onKey(int primaryCode, int[] keyCodes) {        
3
    InputConnection ic = getCurrentInputConnection();
4
    playClick(primaryCode);
5
    switch(primaryCode){
6
    case Keyboard.KEYCODE_DELETE :
7
        ic.deleteSurroundingText(1, 0);
8
        break;
9
    case Keyboard.KEYCODE_SHIFT:
10
        caps = !caps;
11
        keyboard.setShifted(caps);
12
        kv.invalidateAllKeys();
13
        break;
14
    case Keyboard.KEYCODE_DONE:
15
        ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
16
        break;
17
    default:
18
        char code = (char)primaryCode;
19
        if(Character.isLetter(code) && caps){
20
            code = Character.toUpperCase(code);
21
        }
22
        ic.commitText(String.valueOf(code),1);                  
23
    }
24
}

8. Тестирование клавиатуры

Итак, экранная клавиатура готова к тестированию. Скомпилируйте и запустите её  на устройстве Android. Это приложение не имеет Activity, что означает, что оно не появится в панели запуска. Чтобы использовать её, его следует сначала активировать в настройках устройства.

После активации Simple IME откройте любое приложение, которое позволяет вводить текст (например, любое приложение для обмена сообщениями) и понажимайте  по одному из его полей ввода. Вы должны увидеть значок клавиатуры в области уведомлений. В зависимости от вашего устройства вы можете щелкнуть по этому значку или перетащить панель уведомлений вниз и выбрать Simple IME в качестве метода ввода. Теперь вы можете использовать новую клавиатуру.

Заключение

В этом уроке вы научились создавать клавиатуру для Android с нуля. Чтобы изменить внешний вид вашей клавиатуры, все, что вам нужно сделать, это добавить дополнительный стиль в файлы theres / layout / keyboard.xml и res / layout / preview.xml. Чтобы изменить положение клавиш, обновите файл res / xml / qwerty.xml. Чтобы добавить дополнительные функции на клавиатуру, обратитесь к документации разработчика.