- Home
- >> Nerd Digest
- >> Android
-
How to create custom keyboard in android
over 7 years ago
In this tutorial we will learn how to create custom keyboard in android. We can customise keyboard by adding extra buttons, change keyboard theme, set image as keyboard background etc.
Here in this example we are going to add two extra buttons, one for camera and other for gallery, along with qwerty keyboard.
1. First we will create a layout(keyboard.xml) for custom keyboard inside res/layout folder. This layout contains KeyboardView and two buttons.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:id="@+id/mainview" > <android.inputmethodservice.KeyboardView android:id="@+id/keyboard1" android:layout_width="match_parent" android:layout_height="wrap_content" android:keyTextColor="#FFFFFF" android:padding="4px" android:keyTextSize="18sp" android:keyPreviewLayout ="@layout/preview" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="40dp" android:layout_alignParentBottom="true" android:background="@color/colorDarkGray"> <Button android:id="@+id/camera" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toLeftOf="@+id/gallery" android:text="Camera" android:textSize="14sp" android:textColor="@android:color/white" android:background="@color/colorLightGray" android:padding="4px" android:layout_marginRight="5dp" android:layout_marginBottom="5dp"/> <Button android:id="@+id/gallery" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:text="Gallery" android:textSize="14sp" android:textColor="@android:color/white" android:background="@color/colorLightGray" android:padding="4px" android:layout_marginBottom="5dp" /> </RelativeLayout> </LinearLayout>
2. Create another layout file
preview.xml inside
res/layoutfolder. This
layout shows up as a short-lived pop-up whenever a key on the keyboard is pressed. It has a singleTextView
.<?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>
3. A soft keyboard is considered as an Input Method Editor (IME) by Android. Modify manifest file by declaring IME as a service. Provide necessary permission
android.permission.BIND_INPUT_METHOD and set intent filter which matches
android.view.InputMethod.
Modify AndroidManifest.xml file by following lines:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.customkeyboarddemo"> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name="com.customkeyboarddemo.CustomKeyboardService" android:label="@string/simple_ime" android:permission="android.permission.BIND_INPUT_METHOD" android:enabled="true" android:exported="true"> <meta-data android:name="android.view.im" android:resource="@xml/method" /> <intent-filter> <action android:name="android.view.InputMethod" /> </intent-filter> </service> </application> </manifest>
4. The
service
tag in the AndroidManifest file contains ameta-data
tag that references an XML file named method.xml. This file contains details about the input method and its subtypes. Create method.xml file inside res/xml file<?xml version="1.0" encoding="utf-8"?> <input-method xmlns:android="http://schemas.android.com/apk/res/android"> <subtype android:label="subtype_en_US" android:imeSubtypeLocale="en_US" android:imeSubtypeMode="keyboard" /> </input-method>
5. Edit string.xml file
<resources> <string name="app_name">Custom Keyboard Demo</string> <string name="simple_ime">CustomKeyboardDemo</string> <string name="subtype_en_US">English (US)</string> </resources>
6. Edit colors.xml file
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorDarkGray">#2E2E2E</color> <color name="colorLightGray">#585858</color> </resources>
7. The details of the keyboard keys and it's position are defined in an xml file. Every key has the following attributes:
- keyLable: The actual text display on a key.
- codes: This attribute contains the Unicode value of a character, the key represents.
Create qwerty.xml file inside res/xml folder.
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android" android:keyWidth="10%p" android:horizontalGap="0px" android:verticalGap="0px" android:keyHeight="40dp" > <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:keyWidth="20%p" android:keyEdgeFlags="right"/> </Row> <Row> <Key android:codes="-1" android:keyLabel="CAPS" android:keyWidth="20%p" 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>
8. Now create a service class CustomKeyboardService.java which will extend InputMethodService class and implements KeyboardView.OnKeyboardActionListener interface. The OnKeyboardActionListener always called whenever a key is pressed on a keyboard.
When a keyboard is created, the
onCreateInputView
() is called. Initialize all the member variables of theService
class in this method. We also have set click listener for that two extra buttons (camera and gallery).Next, we create a method playClick(int keyCode), that plays a sound when a key is pressed.
Finally, update onKey() method, so that our app's keyboard can communicate with input fields.
Below is the service class:
package com.customkeyboarddemo; import android.content.Context; import android.content.Intent; import android.inputmethodservice.InputMethodService; import android.inputmethodservice.Keyboard; import android.inputmethodservice.KeyboardView; import android.media.AudioManager; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.inputmethod.InputConnection; import android.widget.Button; /** * Created by anita on 21/3/17. */ public class CustomKeyboardService extends InputMethodService implements KeyboardView.OnKeyboardActionListener { private static KeyboardView keyboardView; private Keyboard keyboard; private boolean caps = false; private Button btGallery,btCamera; @Override public View onCreateInputView() { System.out.println("onCreateInputView........."); View view = null; LayoutInflater inflater1 = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater1.inflate(R.layout.keyboard, null); view.invalidate(); keyboardView = (KeyboardView) view.findViewById(R.id.keyboard1); keyboard = new Keyboard(this, R.xml.qwerty); keyboardView.setKeyboard(keyboard); keyboardView.setOnKeyboardActionListener(this); btGallery = (Button)view.findViewById(R.id.gallery); btGallery.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { openCameraOrGallery("gallery"); } }); btCamera = (Button)view.findViewById(R.id.camera); btCamera.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { openCameraOrGallery("camera"); } }); return view; } 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); } } @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); keyboardView.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); } } private void openCameraOrGallery(String str){ Intent intent = new Intent(getBaseContext(), MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); if(str.equals("camera")) intent.putExtra("request", "camera"); else intent.putExtra("request", "gallery"); getApplicationContext().startActivity(intent); } @Override public void onPress(int primaryCode) { } @Override public void onRelease(int primaryCode) { } @Override public void onText(CharSequence text) { } @Override public void swipeLeft() { } @Override public void swipeRight() { } @Override public void swipeDown() { } @Override public void swipeUp() { } @Override public void onCreate() { super.onCreate(); } }
9. Image selected from gallery or captured by camera will show in this application's activity_main.xml file.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.customkeyboarddemo.MainActivity"> <EditText android:id="@+id/edittext" android:layout_width="match_parent" android:layout_height="wrap_content"/> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/imageView" android:layout_below="@id/edittext"/> </RelativeLayout>
10. Finally we have a MainActivity.java class where we will implement functionality to open camera and to select image from gallery
package com.customkeyboarddemo; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.os.Environment; import android.provider.MediaStore; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.ImageView; import java.io.File; public class MainActivity extends AppCompatActivity { private static int RESULT_LOAD_IMAGE = 1; private static int RESULT_CAPTURE_IMAGE = 2; static MainActivity mainActivity; ImageView ivSelectedImage; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mainActivity = this; ivSelectedImage = (ImageView) findViewById(R.id.imageView); if(getIntent().getExtras() != null){ if(getIntent().getStringExtra("request")!= null && getIntent().getStringExtra("request").equals("camera")) openCamera(); else openGallery(); } } @Override protected void onResume(){ super.onResume(); } private void openCamera(){ Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); File f = new File(Environment.getExternalStorageDirectory(),"image.jpg"); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f)); startActivityForResult(intent, RESULT_CAPTURE_IMAGE); } public void openGallery(){ Intent intent; if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) { intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); } else { intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI); } intent.putExtra("return-data", true); intent.setType("image/*"); startActivityForResult(intent, RESULT_LOAD_IMAGE); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Uri selectedImageUri = null; if (resultCode == RESULT_OK) { if (requestCode == RESULT_CAPTURE_IMAGE ) { File f = new File(Environment.getExternalStorageDirectory().toString()+File.separator+"image.jpg"); Uri imgUri = Uri.fromFile(f); selectedImageUri = imgUri; }else if (requestCode == RESULT_LOAD_IMAGE) { // Get the url from data selectedImageUri = data.getData(); } if(null != selectedImageUri) { ivSelectedImage.setImageURI(selectedImageUri); } } } }
11. The custom keyboard is ready to use. Compile your code and run it on an Android device. To use this, it should first be activated on device and you can do it from settings:
Settings --> Language & input --> Current Keyboard --> select your keyboard
Now, you are ready to use your custom keyboard from any app in your device.
Thanks.
0 Comment(s)