Как написать клавиатуру для android

Время на прочтение
5 мин

Количество просмотров 39K

Здравствуйте. В данной статье я постараюсь рассказать и показать основные моменты написания собственной клавиатуры для Android’а. Статья предназначена для разработчиков, которые с этим не сталкивались, но имеют опыт знакомства с Android’ом.

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

Для начала необходимо создать пустой Android проект без Activity. После этого приступим к подготовке .xml файлов, которые будут описывать Android’у нашу клавиатуру.

Базовый layout-файл, keyboard.xml

Содержит в себе View класс Android’а под названием KeyboardView и описывает внешний вид клавиатуры.

<?xml version="1.0" encoding="utf-8"?>
<android.inputmethodservice.KeyboardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/keyboard"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:keyPreviewHeight="35dp"
    android:keyPreviewLayout="@layout/preview" />

Атрибуты:

  • android: keyPreviewHeight — задает высоту элемента подсказки, на котором отображается текущая нажатая клавиша.
  • android:keyPreviewLayout — указываем layout-файл, который описывает внешний вид preview’шки.

Код preview:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:background="@color/key_preview_background"
    android:textColor="@color/key_preview_text_color"
    android:textStyle="bold"
    android:textSize="25sp" />

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

Описание раскладки

Итак, мы подготовили 2 .xml файла, которые описывают внешний вид, теперь настал черед описать саму раскладку клавиатуры. Назовем этот файл keys_definition_ru.xml и находится он будет в xml ресурсах проекта. Здесь будет представлен лишь его кусок, так как файл достаточно большой.

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="7.5%p"
    android:horizontalGap="5px"
    android:verticalGap="0px"
    android:keyHeight="40dp">

    <Row>
        <Key android:codes="-1" android:keyIcon="@drawable/ic_keyboard_capslock_white_24dp"
            android:keyWidth="13%p" android:keyEdgeFlags="left" />
        <Key android:codes="1103" android:keyLabel="я"  />
        <Key android:codes="1095" android:keyLabel="ч" />
        <Key android:codes="1089" android:keyLabel="с" />
        <Key android:codes="1084" android:keyLabel="м" />
        <Key android:codes="1080" android:keyLabel="и" />
        <Key android:codes="1090" android:keyLabel="т" />
        <Key android:codes="1100" android:keyLabel="ь" />
        <Key android:codes="1073" android:keyLabel="б" />
        <Key android:codes="1102" android:keyLabel="ю" />
        <Key android:codes="-5" android:keyIcon="@drawable/ic_backspace_white_24dp"
            android:isRepeatable="true" android:keyEdgeFlags="right" android:keyWidth="13%p" />
    </Row>
</Keyboard>

Атрибуты:

Все атрибуты описывать не будем, лишь «не очевидные».

  • android:horizontalGap — горизонтальный отступ между клавишами
  • android: verticalGap — вертикальный отступ
  • android:codes — код нужного символа в html utf-8 (и не только utf-8, подробнее в оф. документации)
  • android:keyEdgeFlags — атрибут может применять значение left или right. Эти атрибуты добавляются клавишам, которые расположены в самом левом крае или самом правом крае клавиатуры
  • android:isRepeatable — повторять действие клавиши при долгом нажатии (обычно используется на пробеле или backspace)

Заключительный файл — описание локализаций (подтипов инпута):

<?xml version="1.0" encoding="utf-8"?>
<input-method xmlns:android="http://schemas.android.com/apk/res/android">
    <subtype
        android:label="@string/subtype_en_US"
        android:imeSubtypeLocale="en_US"
        android:imeSubtypeMode="keyboard" />
    <subtype
        android:label="@string/subtype_ru_RU"
        android:imeSubtypeLocale="ru_RU"
        android:imeSubtypeMode="keyboard" />
</input-method>

InputMethodService — сервис клавиатуры

Теперь, после того как мы создали все необходимые xml файлы, приступаем к описанию сервиса, который будет слушать события InputMethod.

Для этого создадим сервис, наследуясь от InputMethodService и сразу реализуем интерфейс KeyboardView.OnKeyboardActionListener. В итоге у вас получиться набор методов, которые вы можете переопределить и наполнить необходимой функциональностью, которые позволяют широко кастомизировать вашу клавиатуру. Но здесь я приведу лишь примеры базовых моментов.

Методы onCreateInputView и onKey

    @Override
    public View onCreateInputView() {
        mKeyboardView = (KeyboardView) getLayoutInflater().inflate(R.layout.keyboard, null);
        mKeyboard = new Keyboard(this, R.xml.keys_definition_ru);
        mKeyboard.setShifted(isCapsOn);  //приводим клавиатуру к верхнему регистру, если шифт нажат включен
        mKeyboardView.setKeyboard(mKeyboard);
        mKeyboardView.setOnKeyboardActionListener(this);

        return mKeyboardView;
    }

    @Override
    public void onKey(int primaryCode, int[] ints) {
        Log.d(TAG, "onKey " + primaryCode);
        InputConnection ic = getCurrentInputConnection();
        playClick(primaryCode);

        switch (primaryCode) {
            case Keyboard.KEYCODE_DELETE:
                ic.deleteSurroundingText(1, 0);
                break;
            case Keyboard.KEYCODE_SHIFT:
                handleShift();
                break;
            case Keyboard.KEYCODE_DONE:
                ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
                break;
            case Keyboard.KEYCODE_ALT:
                handleSymbolsSwitch();
                break;
            case Keyboard.KEYCODE_MODE_CHANGE:
                handleLanguageSwitch();
                break;
            default:
                char code = (char) primaryCode;
                if (Character.isLetter(code) && isCapsOn) {
                    code = Character.toUpperCase(code);
                }

                ic.commitText(String.valueOf(code), 1);
                break;
        }
    }

Одним из методов жизненного цикла InputMethodService является onCreateInputView внутри которого мы создаем View клавиатуры и привязываем к ней необходимые листенеры.

Событие onKey срабатывает между onPress и onRelease, на вход им подается код нажатой клавиши.

Итак, все готово… почти, осталось добавить наш сервис в манифест.

<service android:name=".SimpleIME"
            android:label="@string/simple_ime"
            android:permission="android.permission.BIND_INPUT_METHOD">
            <meta-data android:name="android.view.im" android:resource="@xml/method" />
            <intent-filter>
                <action android:name="android.view.InputMethod" />
            </intent-filter>
        </service>

Поздравляю, вы написали свою первую клавиатуру!

→ Исходный код клавиатуры (по умолчанию в ней включен капс)
→ Официальная документация / туториал

Большинство устройств 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. Чтобы добавить дополнительные функции на клавиатуру, обратитесь к документации разработчика.

Разработка под Android


Рекомендация: подборка платных и бесплатных курсов Python — https://katalog-kursov.ru/

Здравствуйте. В данной статье я постараюсь рассказать и показать основные моменты написания собственной клавиатуры для Android’а. Статья предназначена для разработчиков, которые с этим не сталкивались, но имеют опыт знакомства с Android’ом.

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

Для начала необходимо создать пустой Android проект без Activity. После этого приступим к подготовке .xml файлов, которые будут описывать Android’у нашу клавиатуру.

Базовый layout-файл, keyboard.xml

Содержит в себе View класс Android’а под названием KeyboardView и описывает внешний вид клавиатуры.

<?xml version="1.0" encoding="utf-8"?>
<android.inputmethodservice.KeyboardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/keyboard"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:keyPreviewHeight="35dp"
    android:keyPreviewLayout="@layout/preview" />

Атрибуты:

  • android: keyPreviewHeight — задает высоту элемента подсказки, на котором отображается текущая нажатая клавиша.
  • android:keyPreviewLayout — указываем layout-файл, который описывает внешний вид preview’шки.

Код preview:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:background="@color/key_preview_background"
    android:textColor="@color/key_preview_text_color"
    android:textStyle="bold"
    android:textSize="25sp" />

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

Описание раскладки

Итак, мы подготовили 2 .xml файла, которые описывают внешний вид, теперь настал черед описать саму раскладку клавиатуры. Назовем этот файл keys_definition_ru.xml и находится он будет в xml ресурсах проекта. Здесь будет представлен лишь его кусок, так как файл достаточно большой.

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="7.5%p"
    android:horizontalGap="5px"
    android:verticalGap="0px"
    android:keyHeight="40dp">

    <Row>
        <Key android:codes="-1" android:keyIcon="@drawable/ic_keyboard_capslock_white_24dp"
            android:keyWidth="13%p" android:keyEdgeFlags="left" />
        <Key android:codes="1103" android:keyLabel="я"  />
        <Key android:codes="1095" android:keyLabel="ч" />
        <Key android:codes="1089" android:keyLabel="с" />
        <Key android:codes="1084" android:keyLabel="м" />
        <Key android:codes="1080" android:keyLabel="и" />
        <Key android:codes="1090" android:keyLabel="т" />
        <Key android:codes="1100" android:keyLabel="ь" />
        <Key android:codes="1073" android:keyLabel="б" />
        <Key android:codes="1102" android:keyLabel="ю" />
        <Key android:codes="-5" android:keyIcon="@drawable/ic_backspace_white_24dp"
            android:isRepeatable="true" android:keyEdgeFlags="right" android:keyWidth="13%p" />
    </Row>
</Keyboard>

Атрибуты:

Все атрибуты описывать не будем, лишь «не очевидные».

  • android:horizontalGap — горизонтальный отступ между клавишами
  • android: verticalGap — вертикальный отступ
  • android:codes — код нужного символа в html utf-8 (и не только utf-8, подробнее в оф. документации)
  • android:keyEdgeFlags — атрибут может применять значение left или right. Эти атрибуты добавляются клавишам, которые расположены в самом левом крае или самом правом крае клавиатуры
  • android:isRepeatable — повторять действие клавиши при долгом нажатии (обычно используется на пробеле или backspace)

Заключительный файл — описание локализаций (подтипов инпута):

<?xml version="1.0" encoding="utf-8"?>
<input-method xmlns:android="http://schemas.android.com/apk/res/android">
    <subtype
        android:label="@string/subtype_en_US"
        android:imeSubtypeLocale="en_US"
        android:imeSubtypeMode="keyboard" />
    <subtype
        android:label="@string/subtype_ru_RU"
        android:imeSubtypeLocale="ru_RU"
        android:imeSubtypeMode="keyboard" />
</input-method>

InputMethodService — сервис клавиатуры

Теперь, после того как мы создали все необходимые xml файлы, приступаем к описанию сервиса, который будет слушать события InputMethod.

Для этого создадим сервис, наследуясь от InputMethodService и сразу реализуем интерфейс KeyboardView.OnKeyboardActionListener. В итоге у вас получиться набор методов, которые вы можете переопределить и наполнить необходимой функциональностью, которые позволяют широко кастомизировать вашу клавиатуру. Но здесь я приведу лишь примеры базовых моментов.

Методы onCreateInputView и onKey

    @Override
    public View onCreateInputView() {
        mKeyboardView = (KeyboardView) getLayoutInflater().inflate(R.layout.keyboard, null);
        mKeyboard = new Keyboard(this, R.xml.keys_definition_ru);
        mKeyboard.setShifted(isCapsOn);  //приводим клавиатуру к верхнему регистру, если шифт нажат включен
        mKeyboardView.setKeyboard(mKeyboard);
        mKeyboardView.setOnKeyboardActionListener(this);

        return mKeyboardView;
    }

    @Override
    public void onKey(int primaryCode, int[] ints) {
        Log.d(TAG, "onKey " + primaryCode);
        InputConnection ic = getCurrentInputConnection();
        playClick(primaryCode);

        switch (primaryCode) {
            case Keyboard.KEYCODE_DELETE:
                ic.deleteSurroundingText(1, 0);
                break;
            case Keyboard.KEYCODE_SHIFT:
                handleShift();
                break;
            case Keyboard.KEYCODE_DONE:
                ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
                break;
            case Keyboard.KEYCODE_ALT:
                handleSymbolsSwitch();
                break;
            case Keyboard.KEYCODE_MODE_CHANGE:
                handleLanguageSwitch();
                break;
            default:
                char code = (char) primaryCode;
                if (Character.isLetter(code) && isCapsOn) {
                    code = Character.toUpperCase(code);
                }

                ic.commitText(String.valueOf(code), 1);
                break;
        }
    }

Одним из методов жизненного цикла InputMethodService является onCreateInputView внутри которого мы создаем View клавиатуры и привязываем к ней необходимые листенеры.

Событие onKey срабатывает между onPress и onRelease, на вход им подается код нажатой клавиши.

Итак, все готово… почти, осталось добавить наш сервис в манифест.

<service android:name=".SimpleIME"
            android:label="@string/simple_ime"
            android:permission="android.permission.BIND_INPUT_METHOD">
            <meta-data android:name="android.view.im" android:resource="@xml/method" />
            <intent-filter>
                <action android:name="android.view.InputMethod" />
            </intent-filter>
        </service>

Поздравляю, вы написали свою первую клавиатуру!

> Исходный код клавиатуры (по умолчанию в ней включен капс)
> Официальная документация / туториал

Сегодня мы научимся делать не что то там, а самую настоящую клавиатуру со всем стандартным набором возможностей, которую при желании вы сможете даже использовать на своем Android устройстве вместо стандартной (ну представьте себе — печатать смс-ки на собственной клавиатуре, что может быть лучше:)). Если вы думаете, что урок будет очень сложным — то вы правы вы ошибаетесь. Оказывается, что  в стандартном функционале Android SDK Manager есть абсолютно все необходимое для создания полноценной клавиатуры без лишних страданий. Нам не нужно будет ни вырисовывать внешний вид клавиш, ни настраивать распознавание нажатий клавиш, ни мучиться с привязыванием нашей будущей клавиатуры к полям ввода. Все это уже по умолчанию есть в SDK Manager, нам только осталось научиться этим воспользоваться!

Начнем. Создаем новый проект, я назвал его Keyboard (как мы неоднократно договаривались — все названия на ваше усмотрение, только лишь бы вы сами в них не путались). На том шаге, когда нам предлагается создать какую либо Activity, выбираем Add No Activity и жмем финиш. 

Перво наперво, что нам нужно сделать это получить для нашего приложения разрешение ему быть клавиатурой:). Мы хотим создать свое устройство ввода, что называется Input Method Editor (IME), оно определяется в файле манифеста как Service, использующий разрешение BIND_INPUT_METHOD и соответствует действию android.view.InputMethod.  Идем в файл манифеста AndroidManifest.xml и добавляем в тег <application> следующее:

<service android:name="IME"
 android:label="@string/ime"
 android:permission="android.permission.BIND_INPUT_METHOD"
 >
 <meta-data android:name="android.view.im" android:resource="@layout/method"/>
 <intent-filter>
 <action android:name="android.view.InputMethod" />
 </intent-filter> 
</service>

Видим красные подчеркивания (нам не привыкать), не волнуемся. 

Тег Service содержит тег <meta-data>, который ссылается на несуществующий пока файл method.xml. без этого файла ОС Android не признает нашу клавиатуру как корректный метол ввода, который можно использовать.  Этот файл должен содержать подробности о методе ввода и его подтипах. Для нашей клавиатуры определим всего один подтип для en_US локализации (не будем пока экспериментировать с русским, нам главное понять принцип). Создаем в приложении res/layout папку и создаем в ней нужный нам файл  method.xml. Вносим в файл res/layout/mehod.xml следующее:

<?xml version="1.0" encoding="utf-8"?>
<input-method xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_height="wrap_content"
 android:layout_width="wrap_content">
 <subtype
 android:label="@string/subtype_en_US"
 android:imeSubtypeLocale="en_US"
 android:imeSubtypeMode="keyboard" />
</input-method>

Теперь  давайте отредактируем файл строковых ресурсов res/values/strings.xml. Нам нужно добавить сюда строки для:

     — имя приложения;

     — название для IME;

     — название для подтипа IME;

Имя приложения у нас уже есть, остается только добавить две нужные строчки. Отредактированный файл strings.xml выглядит так:

<resources>
 <string name="app_name">Keyboard</string>
 <string name="ime">IME</string>
 <string name="subtype_en_US">English (US)</string>
</resources>

Теперь нужно определить внешний вид клавиатуры. Файл layout для нашей клавиатуры будет содержать только один объект — KeyboardView.  Для того, чтобы наша клавиатура появлялась в низу экрана, настроим атрибут layout_alignParentBottom со значением true. Создаем файл res/layout/keyboard.xml следующее:

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

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

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

Теперь нужно определить клавиши клавиатуры. Подробное описание клавиш и их расположение описывается в специальном .xml файле.  Каждая клавиша имеет следующие атрибуты:
     — keyLabel — название клавиши, которое будет отображаться на клавише;

     — codes — этот атрибут содержит уникальный код, который характеризует нажатую клавишу.

Каждая клавиша, будь то цифра, буква, какой — либо знач имеют свой собственный уникальный код. Например, буква А имеет значение  codes — 97, соответственно keyLabel нужно придать значение «А». Одной клавише можно задать несколько значений в атрибут codes, то клавиша будет принимать определенное значение из этих троих а зависимости от того, сколько раз мы нажали на клавишу (вспомните клавиатурный набор на старых мобильных — на одной клавише «а,б,в,г» и т.д.). Например, если мы зададим кнопке коды 63,33 и 58 то при одном нажатии получим символ «?», при двух нажатиях в короткой последовательности получим «!», а при троих нажатиях — двоеточие «:».

 Клавиша может иметь еще несколько атрибутов:

     — keyEdgeFlags — атрибут может применять значение left или right. Эти атрибуты добавляются клавишам, которые расположены в самом левом или самом правом положении, соответственно;

     — keyWidth — определяет ширину клавиши. Как правило задается в процентах;

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

Клавиши в клавиатуре сгруппированы в колонки. Довольно практично делать по 10 клавиш в колонке и каждой клавише отдавать 10% ширины от общей ширины клавиатуры. Мы выставим высоту клавиш равную 60dp. Можно ее изменять, но не рекомендуется делать высоту меньше 48dp. У нас будет 5 столбцов клавиш.

Переходим от теории к действию. Создаем файл res/layout/qwerty.xml. Файл должен содержать следующий код:
 

<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
 android:keyWidth="10%p"
 android:horizontalGap="0px"
 android:verticalGap="0px"
 android:keyHeight="60dp"
 android:layout_height="wrap_content"
 android:layout_width="wrap_content">
 <Row>
 <Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"/>
 <Key android:codes="50" android:keyLabel="2"/>
 <Key android:codes="51" android:keyLabel="3"/>
 <Key android:codes="52" android:keyLabel="4"/>
 <Key android:codes="53" android:keyLabel="5"/>
 <Key android:codes="54" android:keyLabel="6"/>
 <Key android:codes="55" android:keyLabel="7"/>
 <Key android:codes="56" android:keyLabel="8"/>
 <Key android:codes="57" android:keyLabel="9"/>
 <Key android:codes="48" android:keyLabel="0" android:keyEdgeFlags="right"/>
 </Row>
 <Row>
 <Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/>
 <Key android:codes="119" android:keyLabel="w"/>
 <Key android:codes="101" android:keyLabel="e"/>
 <Key android:codes="114" android:keyLabel="r"/>
 <Key android:codes="116" android:keyLabel="t"/>
 <Key android:codes="121" android:keyLabel="y"/>
 <Key android:codes="117" android:keyLabel="u"/>
 <Key android:codes="105" android:keyLabel="i"/>
 <Key android:codes="111" android:keyLabel="o"/>
 <Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/>
 </Row>
 <Row>
 <Key android:codes="97" android:keyLabel="a" android:keyEdgeFlags="left"/>
 <Key android:codes="115" android:keyLabel="s"/>
 <Key android:codes="100" android:keyLabel="d"/>
 <Key android:codes="102" android:keyLabel="f"/>
 <Key android:codes="103" android:keyLabel="g"/>
 <Key android:codes="104" android:keyLabel="h"/>
 <Key android:codes="106" android:keyLabel="j"/>
 <Key android:codes="107" android:keyLabel="k"/>
 <Key android:codes="108" android:keyLabel="l"/>
 <Key android:codes="35,64" android:keyLabel="# @" android:keyEdgeFlags="right"/>
 </Row>
 <Row>
 <Key android:codes="-1" android:keyLabel="CAPS" android:keyEdgeFlags="left"/>
 <Key android:codes="122" android:keyLabel="z"/>
 <Key android:codes="120" android:keyLabel="x"/>
 <Key android:codes="99" android:keyLabel="c"/>
 <Key android:codes="118" android:keyLabel="v"/>
 <Key android:codes="98" android:keyLabel="b"/>
 <Key android:codes="110" android:keyLabel="n"/>
 <Key android:codes="109" android:keyLabel="m"/>
 <Key android:codes="46" android:keyLabel="."/>
 <Key android:codes="63,33,58" android:keyLabel="? ! :" android:keyEdgeFlags="right"/>
 </Row>
 <Row android:rowEdgeFlags="bottom">
 <Key android:codes="44" android:keyLabel="," android:keyWidth="10%p" android:keyEdgeFlags="left"/>
 <Key android:codes="47" android:keyLabel="/" android:keyWidth="10%p" />
 <Key android:codes="32" android:keyLabel="SPACE" android:keyWidth="40%p" android:isRepeatable="true"/>
 <Key android:codes="-5" android:keyLabel="DEL" android:keyWidth="20%p" android:isRepeatable="true"/>
 <Key android:codes="-4" android:keyLabel="DONE" android:keyWidth="20%p" android:keyEdgeFlags="right"/>
 </Row>
</Keyboard>

Некоторые клавиши могут иметь отрицательное значение атрибута codes, они эквиваленты встроенным константам в класс Keyboard. Например, значение -5 соответствует значению Keyboard.KEYCODE_DELETE

Теперь создадим новый Java класс и назовем его IME.java. Он должен наследовать класс InputMethodService и выполнять интерфейс OnKeyboardActionListener. Этот интерфейс содержит методы, которые вызываются при нажатии на клавиши. 

Класс IME должен иметь 3 типа переменных:

     — KeyboardView — ссылающийся на вид, определенный в layout файле;

     — Keyboard — применяет то, что было назначено в KeyboardView;

     — boolean — сообщает о включенном caps lock-е. 

Если проделать все сказанное, наш файл IME.java приобретает вид:

package home.keyboard;

import android.inputmethodservice.InputMethodService;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;

public class IME extends InputMethodService implements KeyboardView.OnKeyboardActionListener{

 private KeyboardView kv;
 private Keyboard keyboard;

 private boolean caps = false;

 @Override
 public void onPress(int primaryCode) {
 }
 @Override
 public void onRelease(int primaryCode) {
 }
 @Override
 public void onKey(int primaryCode, int[] keyCodes) {
 }
 @Override
 public void onText(CharSequence text) {
 }
 @Override
 public void swipeLeft() {
 }
 @Override
 public void swipeRight() {
 }
 @Override
 public void swipeDown() {
 }
 @Override
 public void swipeUp() {
 }
}

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

 @Override
 public View onCreateInputView() {
 kv = (KeyboardView)getLayoutInflater().inflate(R.layout.keyboard, null);
 keyboard = new Keyboard(this, android.R.layout.qwerty);
 kv.setKeyboard(keyboard);
 kv.setOnKeyboardActionListener(this);
 return kv;
 }

Теперь нужно настроить проигрывание звука при нажатии на клавиши. Используем для этого класс AudioManager. Используем стандартные звуки в методе PlayClick. Код блока настройки звука:

private void playClick(int keyCode){
 AudioManager am = (AudioManager)getSystemService(AUDIO_SERVICE);
 switch(keyCode){
 case 32:
 am.playSoundEffect(AudioManager.FX_KEYPRESS_SPACEBAR);
 break;
 case Keyboard.KEYCODE_DONE:
 case 10:
 am.playSoundEffect(AudioManager.FX_KEYPRESS_RETURN);
 break;
 case Keyboard.KEYCODE_DELETE:
 am.playSoundEffect(AudioManager.FX_KEYPRESS_DELETE);
 break;
 default: am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD);
 }
 }

Теперь нам нужно настроить метод onKey для того, чтобы заставить нашу клавиатуру работать с полями ввода (как правило EditText) других приложений. Для этого используется метод getCurrenrInputConection. Здесь нужно настроить следующее:

     — commitText — для добавления одного или больше символов в поле ввода;

     — deleteSurroundingText — для удаления одного или более символов в поле ввода;

     — sendKeyEvent — отослать событие, типа KEYCODE_ENTER, во внешнее приложение (любое где мы будем использовать нашу клавиатуру).

Каждый раз когда пользователь нажимает на клавишу на клавиатуре вызывается метод onKey, передавая уникальное значение (codes рассмотрено выше) нажатой клавиши. Учитывая значение принятого кода, клавиатура выполняет определенное действие, которое соответствует коду.

Приведите свой метод onKey к такому виду:

@Override
 public void onKey(int primaryCode, int[] keyCodes) {
 InputConnection ic = getCurrentInputConnection();
 playClick(primaryCode);
 switch(primaryCode){
 case Keyboard.KEYCODE_DELETE :
 ic.deleteSurroundingText(1, 0);
 break;
 case Keyboard.KEYCODE_SHIFT:
 caps = !caps;
 keyboard.setShifted(caps);
 kv.invalidateAllKeys();
 break;
 case Keyboard.KEYCODE_DONE:
 ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
 break;
 default:
 char code = (char)primaryCode;
 if(Character.isLetter(code) && caps){
 code = Character.toUpperCase(code);
 }
 ic.commitText(String.valueOf(code),1);
 }
 }

И вот наконец то все! Мы добили наш урок и клавиатура готова к тестированию. Стоит отметить, что так, как наша клавиатура не имеет никакого Activity (Add No Activity, помните?) то ее после установки на эмулятор или устройство не отобразит среди установленных программ. Все дружно идем в настройки — настройки ввода и клавиатуры и там активируем наше творение, как используемый (или один из используемых) метод ввода. Запускаем что либо, где нужно вводить текст, и тестим!

Оригинал этого руководства здесь.

When thinking of building an Android app, we often think of something with a screen and a contained function. It could be a game, or a tool to perform a common task.

But apps can come in a variety of shapes and sizes. You could build a service that runs in the background and quietly makes life easier for the user. You could create a widget, or a launcher. How about a keyboard?

A keyboard can make every interaction quicker, easier and less prone to errors.

Upgrading the software keyboard on your device is one of the most profound ways to customize a device. Most of us use the keyboard as our primary input method. It’s integral to nearly every interaction with your phone. In the best-case scenario, it can make everything quicker, easier, and less error-prone.

Keyboard apps can be highly successful for this reason too; just look at the ubiquity of Swype and SwiftKey.

Whether you just want to take your Android customization to the next level, or you’d like to sell a whole new way to interact with a smart device, read on and let’s explore how to create an Android keyboard.

Note: This project is relatively simple and requires mostly copying and pating XML script. However, it does include some more advanced concepts like services and inheritance. If you’re happy to follow along to get a keyboard running, then anyone should be able to reproduce the app. If you want to understand what everything does, this is a good intermediate project to wrap your head around. You will of course need Android Studio and the Android SDK already set-up.

Layout files. LOTS of layout files

To build our custom keyboard, we’re first going to need to create a new xml file, which will define the layout and appearance of our keyboard. That file will be called keyboard_view.xml. To create this, right click on the “layout” folder in your “res” directory and choose “layout resource file.” In the dialog box that pops up, clear the text where it says “Root element” and start typing “keyboard.” Select the first option which comes up, which should be: android.inputmethodservice.KeyboardView. Call the file keyboard_view.xml (remember, no capitals for resources!).

You will be greeted by a file looking like this:

We’re going to add a few elements now:

Code

android:id="@+id/keyboard_view"
android:keyPreviewLayout="@Layout/key_preview"
android:layout_alignParentBottom="true"
android:background="@color/colorPrimary">

We’ve assigned an ID here so we can refer to the keyboard later in our code. The code aligns our keyboard to the bottom of the screen and the background color is set to colorPrimary. This color is the one set in our values > colors.xml file — it’s easy to change later on. So just hop in there and change the respective color code to change the look a little.

We’ve also referred to another layout for “keyboard preview.” In case you’re scratching your head, that’s the image of the key that flashes up in a large font when you make contact. This assures the user they hit the right key.

As you’ve possibly guessed, this means we need another new layout file, the aforementioned keyboard_preview.xml. Create it in just the same way, though the root element this time is TextView.

Code

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent" android:layout_height="match_parent"
     android:background="@color/colorPrimaryDark"
     android:textColor="@color/colorPrimary"
     android:textAlignment="center"
     android:textSize="30sp">
 
 </TextView>

Add this code and you’ll define the color of the square and the color of the letter appearing in the square. I also set the alignment to center, which ensures it looks the way it should.

The next new XML file is called method.xml. This will go in your resources folder and have the root element input-method. This file will tell Android what type of input is available through your app. Again, you want to replace the boilerplate code that’s there so that it reads like this:

Code

<input-method xmlns:android="http://schemas.android.com/apk/res/android">
     <subtype android:imeSubtypeMode="keyboard" />
 </input-method>

You can also put information such as language in here later on.

This is where we will create the layout for our keyboard — it’s nearly the fun part!

Java tutorial

That will go in a new directory you’ll create (res — xml) and I’m calling mine keys_layout.xml. Replace the code that’s there with this:

Code

<?xml version="1.0" encoding="utf-8"?>
 <Keyboard xmlns:android="http://schemas.android.com/apk/res/android">
     
 </Keyboard>

This is what we’ll be populating with the keys and their behaviors.

Designing your keyboard

We’ve built a bunch of XML files and now we’re ready to start having some fun. It’s time to create the layout of the keys!

This is what I used. It’s basically a slightly tweaked version of a keyboard layout I found online, with the keys all in standard rows. It’s not exactly beautiful, but it’ll do.

Code

<?xml version="1.0" encoding="utf-8"?>
 <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
     android:horizontalGap="3px"
     android:verticalGap="3px"
     android:keyHeight="60dp"
     android:keyTextColor="@color/colorAccent"
     android:keyBackground="@color/colorPrimaryDark"
     >
     <Row>
         <Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"/>
         <Key android:codes="50" android:keyLabel="2"/>
         <Key android:codes="51" android:keyLabel="3"/>
         <Key android:codes="52" android:keyLabel="4"/>
         <Key android:codes="53" android:keyLabel="5"/>
         <Key android:codes="54" android:keyLabel="6"/>
         <Key android:codes="55" android:keyLabel="7"/>
         <Key android:codes="56" android:keyLabel="8"/>
         <Key android:codes="57" android:keyLabel="9"/>
         <Key android:codes="48" android:keyLabel="0"/>
         <Key android:codes="-5" android:keyLabel="DEL" android:keyWidth="20%p" android:isRepeatable="true" android:keyEdgeFlags="right"/>
     </Row>
     <Row>
         <Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/>
         <Key android:codes="119" android:keyLabel="w"/>
         <Key android:codes="101" android:keyLabel="e"/>
         <Key android:codes="114" android:keyLabel="r"/>
         <Key android:codes="116" android:keyLabel="t"/>
         <Key android:codes="121" android:keyLabel="y"/>
         <Key android:codes="117" android:keyLabel="u"/>
         <Key android:codes="105" android:keyLabel="i"/>
         <Key android:codes="111" android:keyLabel="o"/>
         <Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/>
     </Row>
     <Row>
         <Key android:codes="97" android:keyLabel="a" android:keyEdgeFlags="left"/>
         <Key android:codes="115" android:keyLabel="s"/>
         <Key android:codes="100" android:keyLabel="d"/>
         <Key android:codes="102" android:keyLabel="f"/>
         <Key android:codes="103" android:keyLabel="g"/>
         <Key android:codes="104" android:keyLabel="h"/>
         <Key android:codes="106" android:keyLabel="j"/>
         <Key android:codes="107" android:keyLabel="k"/>
         <Key android:codes="108" android:keyLabel="l"/>
         <Key android:codes="35,64" android:keyLabel="# @" android:keyEdgeFlags="right"/>
     </Row>
     <Row>
         <Key android:codes="-1" android:keyLabel="CAPS" android:keyEdgeFlags="left"/>
         <Key android:codes="122" android:keyLabel="z"/>
         <Key android:codes="120" android:keyLabel="x"/>
         <Key android:codes="99" android:keyLabel="c"/>
         <Key android:codes="118" android:keyLabel="v"/>
         <Key android:codes="98" android:keyLabel="b"/>
         <Key android:codes="110" android:keyLabel="n"/>
         <Key android:codes="109" android:keyLabel="m"/>
         <Key android:codes="46" android:keyLabel="."/>
         <Key android:codes="63,33,58" android:keyLabel="? ! :" android:keyEdgeFlags="right"/>
     </Row>
     <Row android:rowEdgeFlags="bottom">
         <Key android:codes="44" android:keyLabel="," android:keyWidth="10%p"  android:keyEdgeFlags="left"/>
         <Key android:codes="47" android:keyLabel="/" android:keyWidth="10%p" />
         <Key android:codes="32" android:keyLabel="SPACE" android:keyWidth="60%p" android:isRepeatable="true"/>
         <Key android:codes="-4" android:keyBackground="@color/colorPrimary" android:keyLabel="DONE" android:keyWidth="20%p" android:keyEdgeFlags="right"/>
     </Row>
 </Keyboard>

You’ll notice a few interesting things here. The android:codes tell us what each key needs to do. This is what we’ll be receiving through our service shortly and you need to make sure the keyLabel (the text on the keys) lines up with what it actually does. Well, unless your objective is to create a “troll keyboard.”

If you place more than one code separated by commas, your keys will scroll through those options if the user double or triple taps. That way we can make a keyboard that works like the old T9 numpad keyboards on Nokia phones, for instance.

Negative codes represent the constants in the keyboard class. -5 is the equivalent of KEYCODE_DELETE. Play around, use your imagination, and see if you can come up with a “better keyboard.”

Android studio development coffee shop

An obvious choice is to make the more popular keys a little larger. That’s what I’ve started doing.

At your service

Now it’s time to create a java class. This is going to be called MyInputMethodService and, as the name suggests, it’s going to be a service. The superclass will be android.inputmethodservice, meaning it will inherit properties from that kind of class and behave like an input method service should (politely).

Under Interface(s), we’ll be implementing OnKeyboardActionListener. Start typing and then select the suggestion that springs up.

Being a service, this means your app can run in the background and then listen out for the moment when it is needed – when the user selects an edit text in another application for example.

Your class will be underlined red when this is generated, which is because it needs to implement the methods from InputMethodService. You can generate this automatically by right clicking on your class and choosing generate — implement methods.

Here’s what it should look like:

Code

public class MyInputMethodService extends InputMethodService implements KeyboardView.OnKeyboardActionListener {
 
 
     public MyInputMethodService() {
         super();
     }
     
     @Override
     public void onPress(int i) {
 
     }
 
     @Override
     public void onRelease(int i) {
 
     }
 
     @Override
     public void onKey(int i, int[] ints) {
 
     }
 
     @Override
     public void onText(CharSequence charSequence) {
 
     }
 
     @Override
     public void swipeLeft() {
 
     }
 
     @Override
     public void swipeRight() {
 
     }
 
     @Override
     public void swipeDown() {
 
     }
 
     @Override
     public void swipeUp() {
 
     }
 }

You also need to override the onCreateInputView() method, which is going to grab the keyboard view and add the layout onto it.

Now add the following code, remembering to import all classes as necessary.

Code

private KeyboardView keyboardView;
 private Keyboard keyboard;
 
 private boolean caps = false;
 
 @Override
 public View onCreateInputView() {
     keyboardView = (KeyboardView) getLayoutInflater().inflate(R.layout.keyboard_view, null);
     keyboard = new Keyboard(this, R.xml.keys_layout);
     keyboardView.setKeyboard(keyboard);
     keyboardView.setOnKeyboardActionListener(this);
     return keyboardView;
 }

When the input view is created, it takes the layout file keyboard_view and uses it to define how it looks. It also adds the keys_layout file we created and returns the view for the system to use.

I’ve also added a Boolean (true or false variable) called caps so we can keep track of caps-lock.

The other important method here, is the one handling key presses. Try this:

Code

@Override
 public void onKey(int primaryCode, int[] keyCodes) {
     InputConnection inputConnection = getCurrentInputConnection();
     if (inputConnection != null) {
         switch(primaryCode) {
             case Keyboard.KEYCODE_DELETE :
                 CharSequence selectedText = inputConnection.getSelectedText(0);
 
                 if (TextUtils.isEmpty(selectedText)) {
                     inputConnection.deleteSurroundingText(1, 0);
                 } else {
                     inputConnection.commitText("", 1);
                 }
             case Keyboard.KEYCODE_SHIFT:
                 caps = !caps;
                 keyboard.setShifted(caps);
                 keyboardView.invalidateAllKeys();
                 break;
             case Keyboard.KEYCODE_DONE:
                 inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
 
                 break;
             default :
                 char code = (char) primaryCode;
                 if(Character.isLetter(code) && caps){
                     code = Character.toUpperCase(code);
                 }
                 inputConnection.commitText(String.valueOf(code), 1);
 
         }
     }
 
 }

This is a switch statement which looks for the key code and acts accordingly. When the user clicks specific keys, the code will change course. KEYCODE_SHIFT changes our caps Boolean, sets the keyboard to “Shifted,” and then invalidates the keys (to redraw them).

Copywriting jobs online

commitText simply sends text (which can include multiple characters) to the input field. sendKeyEvent will send events like “return” to the app.

The class in its entirety should look like this:

Code

public class MyInputMethodService extends InputMethodService implements KeyboardView.OnKeyboardActionListener {
 
     private KeyboardView keyboardView;
     private Keyboard keyboard;
 
     private boolean caps = false;
 
     @Override
     public View onCreateInputView() {
         keyboardView = (KeyboardView) getLayoutInflater().inflate(R.layout.keyboard_view, null);
         keyboard = new Keyboard(this, R.xml.keys_layout);
         keyboardView.setKeyboard(keyboard);
         keyboardView.setOnKeyboardActionListener(this);
         return keyboardView;
     }
 
     @Override
     public void onPress(int i) {
 
     }
 
     @Override
     public void onRelease(int i) {
 
     }
 
 
 
     @Override
     public void onKey(int primaryCode, int[] keyCodes) {
         InputConnection inputConnection = getCurrentInputConnection();
         if (inputConnection != null) {
             switch(primaryCode) {
                 case Keyboard.KEYCODE_DELETE :
                     CharSequence selectedText = inputConnection.getSelectedText(0);
 
                     if (TextUtils.isEmpty(selectedText)) {
                         inputConnection.deleteSurroundingText(1, 0);
                     } else {
                         inputConnection.commitText("", 1);
                     }
                 case Keyboard.KEYCODE_SHIFT:
                     caps = !caps;
                     keyboard.setShifted(caps);
                     keyboardView.invalidateAllKeys();
                     break;
                 case Keyboard.KEYCODE_DONE:
                     inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
 
                     break;
                 default :
                     char code = (char) primaryCode;
                     if(Character.isLetter(code) && caps){
                         code = Character.toUpperCase(code);
                     }
                     inputConnection.commitText(String.valueOf(code), 1);
 
             }
         }
 
     }
 
 
     @Override
     public void onText(CharSequence charSequence) {
 
     }
 
     @Override
     public void swipeLeft() {
 
     }
 
     @Override
     public void swipeRight() {
 
     }
 
     @Override
     public void swipeDown() {
 
     }
 
     @Override
     public void swipeUp() {
 
     }
 }

Testing it out and customization

In order to test your new keyboard, you’ll need to add it via your device’s settings. To do this, go to Language & Input — Virtual Keyboard — Manage Keyboards and turn on the keyboard you created. Select “OK” a few times to dismiss the notifications.

Now open up any app with a text input and bring up your keyboard. You’ll notice a little keyboard icon in the bottom right. Select that and then pick your app from the list. If all has gone to plan, your keyboard should now spring to life!

Play around with different key sizes, customization and features to create the perfect typing experience.

This is a little confusing for new users, so if you plan on selling this app, it might be a good idea to add some text to the MainActivity.Java file, explaining how to select the keyboard. You could also use this in order to add some customization or settings for the users to tweak.

You could add plenty of customization options. How about letting the user change the height and size of their keyboard? You could let them change the colors, use different icons for the keys (android:keyicon), or change the images entirely (android:keybackground=@drawable/). For more advanced options — like changing the color of each individual key — you’ll need to use Java, not XML.

Another common feature of keyboards is to add sounds on each click. You can do this easily by adding a new method in your service and calling it onKey.

The nice thing is that Android actually provides some sounds for us ready to use, so we can do this very easily:

Code

private void playSound(int keyCode){

    v.vibrate(20);
    am = (AudioManager)getSystemService(AUDIO_SERVICE);
    switch(keyCode){
        case 32:
            am.playSoundEffect(AudioManager.FX_KEYPRESS_SPACEBAR);
            break;
        case Keyboard.KEYCODE_DONE:
        case 10:
            am.playSoundEffect(AudioManager.FX_KEYPRESS_RETURN);
            break;
        case Keyboard.KEYCODE_DELETE:
            am.playSoundEffect(AudioManager.FX_KEYPRESS_DELETE);
            break;
        default: am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD);
    }
}

Now just use playSound() at the top of the onKey method and make sure to create a vibrator and audio manager (private AudioManager am; private Virbator v;). You could just as easily swap out the key sounds for your own in the assets folder, or change the duration and behavior of the virbration.

Closing comments

cording in cafe

Now you have your very own custom keyboard! Another challenge ticked off of your Android development list. Play around with different key sizes, customization, and features to create the perfect typing experience.

Be sure to share your finished products in the comments down below! Happy text-inputting!

When thinking of building an Android app, we often think of something with a screen and a contained function. It could be a game, or a tool to perform a common task.

But apps can come in a variety of shapes and sizes. You could build a service that runs in the background and quietly makes life easier for the user. You could create a widget, or a launcher. How about a keyboard?

A keyboard can make every interaction quicker, easier and less prone to errors.

Upgrading the software keyboard on your device is one of the most profound ways to customize a device. Most of us use the keyboard as our primary input method. It’s integral to nearly every interaction with your phone. In the best-case scenario, it can make everything quicker, easier, and less error-prone.

Keyboard apps can be highly successful for this reason too; just look at the ubiquity of Swype and SwiftKey.

Whether you just want to take your Android customization to the next level, or you’d like to sell a whole new way to interact with a smart device, read on and let’s explore how to create an Android keyboard.

Note: This project is relatively simple and requires mostly copying and pating XML script. However, it does include some more advanced concepts like services and inheritance. If you’re happy to follow along to get a keyboard running, then anyone should be able to reproduce the app. If you want to understand what everything does, this is a good intermediate project to wrap your head around. You will of course need Android Studio and the Android SDK already set-up.

Layout files. LOTS of layout files

To build our custom keyboard, we’re first going to need to create a new xml file, which will define the layout and appearance of our keyboard. That file will be called keyboard_view.xml. To create this, right click on the “layout” folder in your “res” directory and choose “layout resource file.” In the dialog box that pops up, clear the text where it says “Root element” and start typing “keyboard.” Select the first option which comes up, which should be: android.inputmethodservice.KeyboardView. Call the file keyboard_view.xml (remember, no capitals for resources!).

You will be greeted by a file looking like this:

We’re going to add a few elements now:

Code

android:id="@+id/keyboard_view"
android:keyPreviewLayout="@Layout/key_preview"
android:layout_alignParentBottom="true"
android:background="@color/colorPrimary">

We’ve assigned an ID here so we can refer to the keyboard later in our code. The code aligns our keyboard to the bottom of the screen and the background color is set to colorPrimary. This color is the one set in our values > colors.xml file — it’s easy to change later on. So just hop in there and change the respective color code to change the look a little.

We’ve also referred to another layout for “keyboard preview.” In case you’re scratching your head, that’s the image of the key that flashes up in a large font when you make contact. This assures the user they hit the right key.

As you’ve possibly guessed, this means we need another new layout file, the aforementioned keyboard_preview.xml. Create it in just the same way, though the root element this time is TextView.

Code

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent" android:layout_height="match_parent"
     android:background="@color/colorPrimaryDark"
     android:textColor="@color/colorPrimary"
     android:textAlignment="center"
     android:textSize="30sp">
 
 </TextView>

Add this code and you’ll define the color of the square and the color of the letter appearing in the square. I also set the alignment to center, which ensures it looks the way it should.

The next new XML file is called method.xml. This will go in your resources folder and have the root element input-method. This file will tell Android what type of input is available through your app. Again, you want to replace the boilerplate code that’s there so that it reads like this:

Code

<input-method xmlns:android="http://schemas.android.com/apk/res/android">
     <subtype android:imeSubtypeMode="keyboard" />
 </input-method>

You can also put information such as language in here later on.

This is where we will create the layout for our keyboard — it’s nearly the fun part!

Java tutorial

That will go in a new directory you’ll create (res — xml) and I’m calling mine keys_layout.xml. Replace the code that’s there with this:

Code

<?xml version="1.0" encoding="utf-8"?>
 <Keyboard xmlns:android="http://schemas.android.com/apk/res/android">
     
 </Keyboard>

This is what we’ll be populating with the keys and their behaviors.

Designing your keyboard

We’ve built a bunch of XML files and now we’re ready to start having some fun. It’s time to create the layout of the keys!

This is what I used. It’s basically a slightly tweaked version of a keyboard layout I found online, with the keys all in standard rows. It’s not exactly beautiful, but it’ll do.

Code

<?xml version="1.0" encoding="utf-8"?>
 <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
     android:horizontalGap="3px"
     android:verticalGap="3px"
     android:keyHeight="60dp"
     android:keyTextColor="@color/colorAccent"
     android:keyBackground="@color/colorPrimaryDark"
     >
     <Row>
         <Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"/>
         <Key android:codes="50" android:keyLabel="2"/>
         <Key android:codes="51" android:keyLabel="3"/>
         <Key android:codes="52" android:keyLabel="4"/>
         <Key android:codes="53" android:keyLabel="5"/>
         <Key android:codes="54" android:keyLabel="6"/>
         <Key android:codes="55" android:keyLabel="7"/>
         <Key android:codes="56" android:keyLabel="8"/>
         <Key android:codes="57" android:keyLabel="9"/>
         <Key android:codes="48" android:keyLabel="0"/>
         <Key android:codes="-5" android:keyLabel="DEL" android:keyWidth="20%p" android:isRepeatable="true" android:keyEdgeFlags="right"/>
     </Row>
     <Row>
         <Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/>
         <Key android:codes="119" android:keyLabel="w"/>
         <Key android:codes="101" android:keyLabel="e"/>
         <Key android:codes="114" android:keyLabel="r"/>
         <Key android:codes="116" android:keyLabel="t"/>
         <Key android:codes="121" android:keyLabel="y"/>
         <Key android:codes="117" android:keyLabel="u"/>
         <Key android:codes="105" android:keyLabel="i"/>
         <Key android:codes="111" android:keyLabel="o"/>
         <Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/>
     </Row>
     <Row>
         <Key android:codes="97" android:keyLabel="a" android:keyEdgeFlags="left"/>
         <Key android:codes="115" android:keyLabel="s"/>
         <Key android:codes="100" android:keyLabel="d"/>
         <Key android:codes="102" android:keyLabel="f"/>
         <Key android:codes="103" android:keyLabel="g"/>
         <Key android:codes="104" android:keyLabel="h"/>
         <Key android:codes="106" android:keyLabel="j"/>
         <Key android:codes="107" android:keyLabel="k"/>
         <Key android:codes="108" android:keyLabel="l"/>
         <Key android:codes="35,64" android:keyLabel="# @" android:keyEdgeFlags="right"/>
     </Row>
     <Row>
         <Key android:codes="-1" android:keyLabel="CAPS" android:keyEdgeFlags="left"/>
         <Key android:codes="122" android:keyLabel="z"/>
         <Key android:codes="120" android:keyLabel="x"/>
         <Key android:codes="99" android:keyLabel="c"/>
         <Key android:codes="118" android:keyLabel="v"/>
         <Key android:codes="98" android:keyLabel="b"/>
         <Key android:codes="110" android:keyLabel="n"/>
         <Key android:codes="109" android:keyLabel="m"/>
         <Key android:codes="46" android:keyLabel="."/>
         <Key android:codes="63,33,58" android:keyLabel="? ! :" android:keyEdgeFlags="right"/>
     </Row>
     <Row android:rowEdgeFlags="bottom">
         <Key android:codes="44" android:keyLabel="," android:keyWidth="10%p"  android:keyEdgeFlags="left"/>
         <Key android:codes="47" android:keyLabel="/" android:keyWidth="10%p" />
         <Key android:codes="32" android:keyLabel="SPACE" android:keyWidth="60%p" android:isRepeatable="true"/>
         <Key android:codes="-4" android:keyBackground="@color/colorPrimary" android:keyLabel="DONE" android:keyWidth="20%p" android:keyEdgeFlags="right"/>
     </Row>
 </Keyboard>

You’ll notice a few interesting things here. The android:codes tell us what each key needs to do. This is what we’ll be receiving through our service shortly and you need to make sure the keyLabel (the text on the keys) lines up with what it actually does. Well, unless your objective is to create a “troll keyboard.”

If you place more than one code separated by commas, your keys will scroll through those options if the user double or triple taps. That way we can make a keyboard that works like the old T9 numpad keyboards on Nokia phones, for instance.

Negative codes represent the constants in the keyboard class. -5 is the equivalent of KEYCODE_DELETE. Play around, use your imagination, and see if you can come up with a “better keyboard.”

Android studio development coffee shop

An obvious choice is to make the more popular keys a little larger. That’s what I’ve started doing.

At your service

Now it’s time to create a java class. This is going to be called MyInputMethodService and, as the name suggests, it’s going to be a service. The superclass will be android.inputmethodservice, meaning it will inherit properties from that kind of class and behave like an input method service should (politely).

Under Interface(s), we’ll be implementing OnKeyboardActionListener. Start typing and then select the suggestion that springs up.

Being a service, this means your app can run in the background and then listen out for the moment when it is needed – when the user selects an edit text in another application for example.

Your class will be underlined red when this is generated, which is because it needs to implement the methods from InputMethodService. You can generate this automatically by right clicking on your class and choosing generate — implement methods.

Here’s what it should look like:

Code

public class MyInputMethodService extends InputMethodService implements KeyboardView.OnKeyboardActionListener {
 
 
     public MyInputMethodService() {
         super();
     }
     
     @Override
     public void onPress(int i) {
 
     }
 
     @Override
     public void onRelease(int i) {
 
     }
 
     @Override
     public void onKey(int i, int[] ints) {
 
     }
 
     @Override
     public void onText(CharSequence charSequence) {
 
     }
 
     @Override
     public void swipeLeft() {
 
     }
 
     @Override
     public void swipeRight() {
 
     }
 
     @Override
     public void swipeDown() {
 
     }
 
     @Override
     public void swipeUp() {
 
     }
 }

You also need to override the onCreateInputView() method, which is going to grab the keyboard view and add the layout onto it.

Now add the following code, remembering to import all classes as necessary.

Code

private KeyboardView keyboardView;
 private Keyboard keyboard;
 
 private boolean caps = false;
 
 @Override
 public View onCreateInputView() {
     keyboardView = (KeyboardView) getLayoutInflater().inflate(R.layout.keyboard_view, null);
     keyboard = new Keyboard(this, R.xml.keys_layout);
     keyboardView.setKeyboard(keyboard);
     keyboardView.setOnKeyboardActionListener(this);
     return keyboardView;
 }

When the input view is created, it takes the layout file keyboard_view and uses it to define how it looks. It also adds the keys_layout file we created and returns the view for the system to use.

I’ve also added a Boolean (true or false variable) called caps so we can keep track of caps-lock.

The other important method here, is the one handling key presses. Try this:

Code

@Override
 public void onKey(int primaryCode, int[] keyCodes) {
     InputConnection inputConnection = getCurrentInputConnection();
     if (inputConnection != null) {
         switch(primaryCode) {
             case Keyboard.KEYCODE_DELETE :
                 CharSequence selectedText = inputConnection.getSelectedText(0);
 
                 if (TextUtils.isEmpty(selectedText)) {
                     inputConnection.deleteSurroundingText(1, 0);
                 } else {
                     inputConnection.commitText("", 1);
                 }
             case Keyboard.KEYCODE_SHIFT:
                 caps = !caps;
                 keyboard.setShifted(caps);
                 keyboardView.invalidateAllKeys();
                 break;
             case Keyboard.KEYCODE_DONE:
                 inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
 
                 break;
             default :
                 char code = (char) primaryCode;
                 if(Character.isLetter(code) && caps){
                     code = Character.toUpperCase(code);
                 }
                 inputConnection.commitText(String.valueOf(code), 1);
 
         }
     }
 
 }

This is a switch statement which looks for the key code and acts accordingly. When the user clicks specific keys, the code will change course. KEYCODE_SHIFT changes our caps Boolean, sets the keyboard to “Shifted,” and then invalidates the keys (to redraw them).

Copywriting jobs online

commitText simply sends text (which can include multiple characters) to the input field. sendKeyEvent will send events like “return” to the app.

The class in its entirety should look like this:

Code

public class MyInputMethodService extends InputMethodService implements KeyboardView.OnKeyboardActionListener {
 
     private KeyboardView keyboardView;
     private Keyboard keyboard;
 
     private boolean caps = false;
 
     @Override
     public View onCreateInputView() {
         keyboardView = (KeyboardView) getLayoutInflater().inflate(R.layout.keyboard_view, null);
         keyboard = new Keyboard(this, R.xml.keys_layout);
         keyboardView.setKeyboard(keyboard);
         keyboardView.setOnKeyboardActionListener(this);
         return keyboardView;
     }
 
     @Override
     public void onPress(int i) {
 
     }
 
     @Override
     public void onRelease(int i) {
 
     }
 
 
 
     @Override
     public void onKey(int primaryCode, int[] keyCodes) {
         InputConnection inputConnection = getCurrentInputConnection();
         if (inputConnection != null) {
             switch(primaryCode) {
                 case Keyboard.KEYCODE_DELETE :
                     CharSequence selectedText = inputConnection.getSelectedText(0);
 
                     if (TextUtils.isEmpty(selectedText)) {
                         inputConnection.deleteSurroundingText(1, 0);
                     } else {
                         inputConnection.commitText("", 1);
                     }
                 case Keyboard.KEYCODE_SHIFT:
                     caps = !caps;
                     keyboard.setShifted(caps);
                     keyboardView.invalidateAllKeys();
                     break;
                 case Keyboard.KEYCODE_DONE:
                     inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
 
                     break;
                 default :
                     char code = (char) primaryCode;
                     if(Character.isLetter(code) && caps){
                         code = Character.toUpperCase(code);
                     }
                     inputConnection.commitText(String.valueOf(code), 1);
 
             }
         }
 
     }
 
 
     @Override
     public void onText(CharSequence charSequence) {
 
     }
 
     @Override
     public void swipeLeft() {
 
     }
 
     @Override
     public void swipeRight() {
 
     }
 
     @Override
     public void swipeDown() {
 
     }
 
     @Override
     public void swipeUp() {
 
     }
 }

Testing it out and customization

In order to test your new keyboard, you’ll need to add it via your device’s settings. To do this, go to Language & Input — Virtual Keyboard — Manage Keyboards and turn on the keyboard you created. Select “OK” a few times to dismiss the notifications.

Now open up any app with a text input and bring up your keyboard. You’ll notice a little keyboard icon in the bottom right. Select that and then pick your app from the list. If all has gone to plan, your keyboard should now spring to life!

Play around with different key sizes, customization and features to create the perfect typing experience.

This is a little confusing for new users, so if you plan on selling this app, it might be a good idea to add some text to the MainActivity.Java file, explaining how to select the keyboard. You could also use this in order to add some customization or settings for the users to tweak.

You could add plenty of customization options. How about letting the user change the height and size of their keyboard? You could let them change the colors, use different icons for the keys (android:keyicon), or change the images entirely (android:keybackground=@drawable/). For more advanced options — like changing the color of each individual key — you’ll need to use Java, not XML.

Another common feature of keyboards is to add sounds on each click. You can do this easily by adding a new method in your service and calling it onKey.

The nice thing is that Android actually provides some sounds for us ready to use, so we can do this very easily:

Code

private void playSound(int keyCode){

    v.vibrate(20);
    am = (AudioManager)getSystemService(AUDIO_SERVICE);
    switch(keyCode){
        case 32:
            am.playSoundEffect(AudioManager.FX_KEYPRESS_SPACEBAR);
            break;
        case Keyboard.KEYCODE_DONE:
        case 10:
            am.playSoundEffect(AudioManager.FX_KEYPRESS_RETURN);
            break;
        case Keyboard.KEYCODE_DELETE:
            am.playSoundEffect(AudioManager.FX_KEYPRESS_DELETE);
            break;
        default: am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD);
    }
}

Now just use playSound() at the top of the onKey method and make sure to create a vibrator and audio manager (private AudioManager am; private Virbator v;). You could just as easily swap out the key sounds for your own in the assets folder, or change the duration and behavior of the virbration.

Closing comments

cording in cafe

Now you have your very own custom keyboard! Another challenge ticked off of your Android development list. Play around with different key sizes, customization, and features to create the perfect typing experience.

Be sure to share your finished products in the comments down below! Happy text-inputting!

Конечный продукт
Что вы будете создавать

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

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

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

Премиум вариант

Если вы спешите, посмотрите Android Keyboard Themes , готовое к использованию решение от Envato Market.

Приложение дает вам возможность выбрать одну из 22 встроенных тем клавиатуры или создать собственную тему.

Темы клавиатуры Android

Темы клавиатуры Android

Или вы можете нанять фрилансера в Envato Studio. Просто просмотрите наш раздел Mobile & Apps, и вы обязательно найдете эксперта, который сможет вам помочь.

Разработчики мобильных приложений и приложений на Envato Studio

Разработчики мобильных приложений и приложений в Envato Studio

Если вы предпочитаете создавать свои собственные, читайте дальше, чтобы узнать, как это сделать.

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

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

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

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

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

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

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

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

1

2

3

4

5

6

7

8

9

<service android:name=”.SimpleIME”

    android:label=”@string/simple_ime”

    android:permission=”android.permission.BIND_INPUT_METHOD”

    >

    <meta-data android:name=”android.view.im” android:resource=”@xml/method”/>

    <intent-filter>

        <action android:name=”android.view.InputMethod” />

    </intent-filter>

</service>

4. Создайте method.xml

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

1

2

3

4

5

6

7

<?xml version=”1.0″ encoding=”utf-8″?>

<input-method xmlns:android=”https://schemas.android.com/apk/res/android”>

    <subtype

        android:label=”@string/subtype_en_US”

        android:imeSubtypeLocale=”en_US”

        android:imeSubtypeMode=”keyboard” />

</input-method>

5. Отредактируйте strings.xml

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

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

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

1

2

3

4

5

<resources>

    <string name=”app_name”>SimpleKeyboard</string>

    <string name=”simple_ime”>Simple IME</string>

    <string name=”subtype_en_US”>English (US)</string>

</resources>

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

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

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

1

2

3

4

5

6

7

8

9

<?xml version=”1.0″ encoding=”UTF-8″?>

<android.inputmethodservice.KeyboardView

    xmlns:android=”http://schemas.android.com/apk/res/android”

    android:id=”@+id/keyboard”

    android:layout_width=”match_parent”

    android:layout_height=”wrap_content”

    android:layout_alignParentBottom=”true”

    android:keyPreviewLayout =”@layout/preview”

/>

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

01

02

03

04

05

06

07

08

09

10

<?xml version=”1.0″ encoding=”utf-8″?>

<TextView xmlns:android=”http://schemas.android.com/apk/res/android”

    android:layout_width=”match_parent”

    android:layout_height=”match_parent”

    android:gravity=”center”

    android:background=”#ffff00″

    android:textStyle=”bold”

    android:textSize=”30sp”

    >

</TextView>

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

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

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

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

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

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

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

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

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

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

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

59

60

61

62

<Keyboard xmlns:android=”http://schemas.android.com/apk/res/android”

    android:keyWidth=”10%p”

    android:horizontalGap=”0px”

    android:verticalGap=”0px”

    android:keyHeight=”60dp”

>

    <Row>

        <Key android:codes=”49″ android:keyLabel=”1″ android:keyEdgeFlags=”left”/>

        <Key android:codes=”50″ android:keyLabel=”2″/>

        <Key android:codes=”51″ android:keyLabel=”3″/>

        <Key android:codes=”52″ android:keyLabel=”4″/>

        <Key android:codes=”53″ android:keyLabel=”5″/>

        <Key android:codes=”54″ android:keyLabel=”6″/>

        <Key android:codes=”55″ android:keyLabel=”7″/>

        <Key android:codes=”56″ android:keyLabel=”8″/>

        <Key android:codes=”57″ android:keyLabel=”9″/>

        <Key android:codes=”48″ android:keyLabel=”0″ android:keyEdgeFlags=”right”/>

    </Row>

    <Row>

        <Key android:codes=”113″ android:keyLabel=”q” android:keyEdgeFlags=”left”/>

        <Key android:codes=”119″ android:keyLabel=”w”/>

        <Key android:codes=”101″ android:keyLabel=”e”/>

        <Key android:codes=”114″ android:keyLabel=”r”/>

        <Key android:codes=”116″ android:keyLabel=”t”/>

        <Key android:codes=”121″ android:keyLabel=”y”/>

        <Key android:codes=”117″ android:keyLabel=”u”/>

        <Key android:codes=”105″ android:keyLabel=”i”/>

        <Key android:codes=”111″ android:keyLabel=”o”/>

        <Key android:codes=”112″ android:keyLabel=”p” android:keyEdgeFlags=”right”/>

    </Row>

    <Row>

        <Key android:codes=”97″ android:keyLabel=”a” android:keyEdgeFlags=”left”/>

        <Key android:codes=”115″ android:keyLabel=”s”/>

        <Key android:codes=”100″ android:keyLabel=”d”/>

        <Key android:codes=”102″ android:keyLabel=”f”/>

        <Key android:codes=”103″ android:keyLabel=”g”/>

        <Key android:codes=”104″ android:keyLabel=”h”/>

        <Key android:codes=”106″ android:keyLabel=”j”/>

        <Key android:codes=”107″ android:keyLabel=”k”/>

        <Key android:codes=”108″ android:keyLabel=”l”/>

        <Key android:codes=”35,64″ android:keyLabel=”# @” android:keyEdgeFlags=”right”/>

    </Row>

    <Row>

        <Key android:codes=”-1″ android:keyLabel=”CAPS” android:keyEdgeFlags=”left”/>

        <Key android:codes=”122″ android:keyLabel=”z”/>

        <Key android:codes=”120″ android:keyLabel=”x”/>

        <Key android:codes=”99″ android:keyLabel=”c”/>

        <Key android:codes=”118″ android:keyLabel=”v”/>

        <Key android:codes=”98″ android:keyLabel=”b”/>

        <Key android:codes=”110″ android:keyLabel=”n”/>

        <Key android:codes=”109″ android:keyLabel=”m”/>

        <Key android:codes=”46″ android:keyLabel=”.”/>

        <Key android:codes=”63,33,58″ android:keyLabel=”? ! :” android:keyEdgeFlags=”right”/>

    </Row>

    <Row android:rowEdgeFlags=”bottom”>

        <Key android:codes=”44″ android:keyLabel=”,” android:keyWidth=”10%p” android:keyEdgeFlags=”left”/>

        <Key android:codes=”47″ android:keyLabel=”/” android:keyWidth=”10%p” />

        <Key android:codes=”32″ android:keyLabel=”SPACE” android:keyWidth=”40%p” android:isRepeatable=”true”/>

        <Key android:codes=”-5″ android:keyLabel=”DEL” android:keyWidth=”20%p” android:isRepeatable=”true”/>

        <Key android:codes=”-4″ android:keyLabel=”DONE” android:keyWidth=”20%p” android:keyEdgeFlags=”right”/>

    </Row>

</Keyboard>

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

7. Создайте класс Service

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

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

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

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

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

public class SimpleIME extends InputMethodService

    implements OnKeyboardActionListener{

    private KeyboardView kv;

    private Keyboard keyboard;

    private boolean caps = false;

    @Override

    public void onKey(int primaryCode, int[] keyCodes) {

    }

    @Override

    public void onPress(int primaryCode) {

    }

    @Override

    public void onRelease(int primaryCode) {

    }

    @Override

    public void onText(CharSequence text) {

    }

    @Override

    public void swipeDown() {

    }

    @Override

    public void swipeLeft() {

    }

    @Override

    public void swipeRight() {

    }

    @Override

    public void swipeUp() {

    }

}

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

1

2

3

4

5

6

7

8

@Override

public View onCreateInputView() {

    kv = (KeyboardView)getLayoutInflater().inflate(R.layout.keyboard, null);

    keyboard = new Keyboard(this, R.xml.qwerty);

    kv.setKeyboard(keyboard);

    kv.setOnKeyboardActionListener(this);

    return kv;

}

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

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

private void playClick(int keyCode){

    AudioManager am = (AudioManager)getSystemService(AUDIO_SERVICE);

    switch(keyCode){

    case 32:

        am.playSoundEffect(AudioManager.FX_KEYPRESS_SPACEBAR);

        break;

    case Keyboard.KEYCODE_DONE:

    case 10:

        am.playSoundEffect(AudioManager.FX_KEYPRESS_RETURN);

        break;

    case Keyboard.KEYCODE_DELETE:

        am.playSoundEffect(AudioManager.FX_KEYPRESS_DELETE);

        break;

    default: am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD);

    }

}

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

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

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

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

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

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

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

@Override

public void onKey(int primaryCode, int[] keyCodes) {

    InputConnection ic = getCurrentInputConnection();

    playClick(primaryCode);

    switch(primaryCode){

    case Keyboard.KEYCODE_DELETE :

        ic.deleteSurroundingText(1, 0);

        break;

    case Keyboard.KEYCODE_SHIFT:

        caps = !caps;

        keyboard.setShifted(caps);

        kv.invalidateAllKeys();

        break;

    case Keyboard.KEYCODE_DONE:

        ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));

        break;

    default:

        char code = (char)primaryCode;

        if(Character.isLetter(code) && caps){

            code = Character.toUpperCase(code);

        }

        ic.commitText(String.valueOf(code),1);

    }

}

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

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

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

Вывод

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

Понравилась статья? Поделить с друзьями:
  • Как написать клава кока
  • Как написать китайскими буквами
  • Как написать коллективную жалобу на учителя от учеников
  • Как написать коллективную жалобу на учителя от родителей образец
  • Как написать коллективную жалобу на ученика от родителей образец