- Home
- >> Nerd Digest
- >> Android
-
How to create Custm Keyboard in Android?
over 8 years ago
Hello Guys,
This is very important tutorial through which, we will learn how to create a custom keyboard without using third party library in the android application. This tutorial fully customizes device keyboard. We will go step by step to learn this process.
Step1- Introduction
Custom keyboard process provides full customization of your device keyboard. Through this tutorial, you can set device keyboard wallpaper, change keyboard themes, change keyboard key background color etc.
Step2- Create two directory colors.xml and strings.xml inside res/values/
colors.xml
?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#3F51B5</color> <color name="colorPrimaryDark">#303F9F</color> <color name="colorAccent">#FF4081</color> <color name="colorTransparent">#20FFFFFF</color> <color name="colorBack">#80AFC2</color> <color name="themes1_keystroke">#6EE0D8</color> <color name="themes1_color1">#5048B6AA</color> <color name="themes1_color2">#501E9799</color> <color name="colorWhite">#FFFFFF</color> <color name="themes2_keystroke">#B8B0A6</color> <color name="themes2_color1">#2D4A73</color> <color name="themes2_color2">#2963B9</color> </resources>
strings.xml
<resources> <string name="app_name">MyKeyboard</string> <string name="action_settings">Settings</string> <string name="simple_ime">MyCustomKeyboard</string> <string name="subtype_en_US">English (US)</string> <string name="keyboad_background">Keyboard Background Image</string> <string name="themedefault">Theme Default</string> <string name="themeone">Theme one</string> <string name="themetwo">Theme two</string> </resources>
Step3- Create a parent directory resource xml under res/xml and put following two more child directory resource method.xml and qwerty.xml.
res/xml/method.xml:
In this resource file, we define keyboard input method such as keyboard default language, keyboard locale language, keyboard mode etc.
<?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>
res/xml/qwerty.xml
This is the important file for a custom keyboard. In this file, we define all keyboard keys row with all numeric and alphabetic. We also define keys height, width and gaps between keys.
<?xml version="1.0" encoding="utf-8"?> <Keyboard xmlns:android="http://schemas.android.com/apk/res/android" android:keyWidth="10%p" android:horizontalGap="8px" android:verticalGap="8px" android:keyHeight="35dp"> <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:keyWidth="18%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="-5" android:keyIcon="@drawable/ic_clear_white_24dp" android:isRepeatable="true"/> </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="46" android:keyLabel="."/> <Key android:codes="63,33,58" android:keyLabel="\? ! :" android:keyEdgeFlags="right"/> <Key android:codes="32" android:keyLabel="SPACE" android:keyWidth="35%p" android:isRepeatable="true"/> <Key android:codes="-4" android:keyLabel="DONE" android:keyWidth="20%p" android:keyEdgeFlags="right"/> </Row> </Keyboard>
Step4- Create a menu resource file to show options for themes and keyboard wallpaper .
res/menu/main_menu.xml
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/action1" android:title="@string/keyboad_background" /> <item android:id="@+id/defaultAction" android:title="@string/themedefault" /> <item android:id="@+id/action2" android:title="@string/themeone" /> <item android:id="@+id/action3" android:title="@string/themetwo" /> </menu>
Step5- Now, we will create custom themes layout file under main layout resource folder
- Default Theme
res/layout/default_theme.xml
<?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="250dp" android:orientation="vertical" android:id="@+id/mainview"> <RelativeLayout android:layout_width="match_parent" android:layout_height="40dp" android:background="@color/colorBack"> <ImageView android:layout_width="wrap_content" android:layout_height="match_parent" android:padding="10dp" android:id="@+id/menu_item" android:layout_alignParentRight="true" android:src="@drawable/ic_more_vert_white_24dp"/> </RelativeLayout> <android.inputmethodservice.KeyboardView android:id="@+id/keyboard" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:keyTextColor="@color/colorAccent" android:padding="4px" android:background="@drawable/images" android:keyTextSize="18sp" android:keyBackground="@color/colorTransparent" android:keyPreviewLayout ="@layout/preview" /> </LinearLayout>
- Theme One
res/layout/themes1.xml
<?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="250dp" android:orientation="vertical" android:id="@+id/mainview"> <RelativeLayout android:layout_width="match_parent" android:layout_height="40dp" android:background="@color/themes1_keystroke"> <ImageView android:layout_width="wrap_content" android:layout_height="match_parent" android:padding="10dp" android:id="@+id/menu_item" android:layout_alignParentRight="true" android:src="@drawable/ic_more_vert_white_24dp"/> </RelativeLayout> <android.inputmethodservice.KeyboardView android:id="@+id/keyboard1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:keyTextColor="@color/colorWhite" android:padding="4px" android:keyTextSize="18sp" android:background="@drawable/images" android:keyBackground="@drawable/themes1_bg" android:keyPreviewLayout ="@layout/preview" /> </LinearLayout>
- Theme two
res/layout/themes2.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="250dp" android:orientation="vertical" android:id="@+id/mainview"> <RelativeLayout android:layout_width="match_parent" android:layout_height="40dp" android:background="@color/themes2_keystroke"> <ImageView android:layout_width="wrap_content" android:layout_height="match_parent" android:padding="10dp" android:id="@+id/menu_item" android:layout_alignParentRight="true" android:src="@drawable/ic_more_vert_white_24dp"/> </RelativeLayout> <android.inputmethodservice.KeyboardView android:id="@+id/keyboard2" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:keyTextColor="@color/colorWhite" android:padding="4px" android:keyTextSize="18sp" android:background="@drawable/images" android:keyBackground="@drawable/themes2_bg" android:keyPreviewLayout ="@layout/preview" /> </LinearLayout>
4- Create parent layout
res/layout/parentlayout.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:id="@+id/parentlayout" android:layout_width="match_parent" android:layout_height="match_parent"> </LinearLayout>
5- Create preview layout
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="30dp" android:gravity="center" android:background="#FFFFFF" android:textStyle="bold" android:textSize="25sp" > </TextView>
Step6- Now we will create main keyboard service MyKeyboardService
MyKeyboardService extends InputMethodService, InputMethodService provides a standard implementation of an InputMethod, which final implementations can derive from and customize.
The InputMethodService
provides a basic framework for standard UI elements (input view, candidates view, and running in fullscreen mode), but it is up to a particular implementor to decide how to use them. For example, one input method could implement an input area with a keyboard, another could allow the user to draw text, while a third could have no input area (and thus not be visible to the user) but instead listen to audio and perform text to speech conversion.Refrence Url:- https://developer.android.com/reference/android/inputmethodservice/InputMethodService.html
MykeyboardService.java
/** * Created by arvind on 8/7/16. */ public class MyKeyboardService extends InputMethodService implements KeyboardView.OnKeyboardActionListener { private static KeyboardView kv; private Keyboard keyboard; private ImageView imageView; private static int RESULT_LOAD_IMAGE = 1; Drawable d; public static LinearLayout linearLayout; private boolean caps = false; private String themes="default"; private static Drawable drawable; @Override public void onKey(int primaryCode, int[] keyCodes) { System.out.println("onKeyPressed."); 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); } } @Override public void onPress(int primaryCode) { System.out.println("onPress"); } @Override public void onRelease(int primaryCode) { System.out.println("onRelease"); } @Override public void onText(CharSequence text) { System.out.println("onText"); } @Override public void swipeDown() { System.out.println("onSwipeDown"); } @Override public void swipeLeft() { System.out.println("onSwipeLeft"); } @Override public void swipeRight() { } @Override public void swipeUp() { } @Override public void onCreate() { super.onCreate(); } @Override public View onCreateInputView() { System.out.println("onCreateInputView........."); View view = null; if (themes != null && themes.equals("one")) { System.out.println("theme one...."); LayoutInflater inflater1 = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater1.inflate(R.layout.themes1, null); view.invalidate(); imageView = (ImageView) view.findViewById(R.id.menu_item); imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { openOptionsMenu(v); } }); kv = (KeyboardView) view.findViewById(R.id.keyboard1); //kv.setBackgroundResource(R.drawable.images); keyboard = new Keyboard(this, R.xml.qwerty); kv.setKeyboard(keyboard); kv.setOnKeyboardActionListener(this); kv.setBackground(drawable); return view; }else if (themes != null && themes.equals("two")) { System.out.println("theme two...."); LayoutInflater inflater1 = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater1.inflate(R.layout.themes2, null); view.invalidate(); imageView = (ImageView) view.findViewById(R.id.menu_item); imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { openOptionsMenu(v); } }); kv = (KeyboardView) view.findViewById(R.id.keyboard2); //kv.setBackgroundResource(R.drawable.images); keyboard = new Keyboard(this, R.xml.qwerty); kv.setKeyboard(keyboard); kv.setOnKeyboardActionListener(this); kv.setBackground(drawable); return view; } else if (themes != null && themes.equals("default")) { System.out.println("theme default...."); LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.default_theme, null); imageView = (ImageView) view.findViewById(R.id.menu_item); imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { openOptionsMenu(v); } }); kv = (KeyboardView) view.findViewById(R.id.keyboard); //kv.setBackgroundResource(R.drawable.images); keyboard = new Keyboard(this, R.xml.qwerty); kv.setKeyboard(keyboard); kv.setOnKeyboardActionListener(this); kv.setBackground(drawable); return view; }else { return null; } } // This function open options menu private void openOptionsMenu(View view){ /** Instantiating PopupMenu class */ PopupMenu popup = new PopupMenu(getBaseContext(), view); /** Adding menu items to the popumenu */ popup.getMenuInflater().inflate(R.menu.menu_main, popup.getMenu()); /** Defining menu item click listener for the popup menu */ popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { Toast.makeText(getBaseContext(), "Click Item " + item.getTitle(), Toast.LENGTH_SHORT).show(); if (item.getTitle().equals("Keyboard Background Image")) { Intent intent = new Intent(getBaseContext(), MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra("from", "service"); getApplicationContext().startActivity(intent); }else if(item.getTitle().equals("Theme one")){ themes="one"; setInputView(onCreateInputView()); }else if(item.getTitle().equals("Theme two")){ themes="two"; setInputView(onCreateInputView()); } else if(item.getTitle().equals("Theme Default")){ themes="default"; setInputView(onCreateInputView()); } return true; } }); /** Showing the popup menu */ popup.show(); } private void playClick(int keyCode){ AudioManager am = (AudioManager)getSystemService(AUDIO_SERVICE); switch(keyCode){ case 32: am.playSoundEffect(AudioManager.FX_KEYPRESS_SPACEBAR); break; case -1: 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); } } public static void setBackGroundImage(Bitmap bitmap){ try { drawable=new BitmapDrawable(Resources.getSystem(),bitmap); kv.setBackground(drawable); }catch (Exception e){ } } }
Step7- Create a MainActivity class
This main class nothing do but use to open gallery when user tries to select images for keyboard wallpaper. In this activity, we need to define two methods which call from InputMethodService. First method is doChangeBackground(), this method call when user will try to change keyboard wallpaper.
MainActivity.java
// Defined class variable
private static int RESULT_LOAD_IMAGE = 1; static MainActivity mainActivity; private Bitmap yourSelectedImage;
// onCreate() method
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.activity_main); mainActivity=this; //String str=getIntent().getStringExtra("from"); if(getIntent().getExtras()!=null){ System.out.println("not null"); doChangeKeyBoardBackground(); }else{ System.out.println("null"); } }
// method call from InputMethodService
// change default_theme background images public void doChangeKeyBoardBackground(){ 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 onActivityResult method
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { if (requestCode == RESULT_LOAD_IMAGE) { // Get the url from data Uri selectedImageUri = data.getData(); if (null != selectedImageUri) { // Get the path from the Uri getPathFromURI(selectedImageUri); // finish(); MyKeyboardService.setBackGroundImage(yourSelectedImage); finish(); } } } } /* Get the real path from the URI */ public String getPathFromURI(Uri contentUri) { String res = null; String[] proj = {MediaStore.Images.Media.DATA}; Cursor cursor = getContentResolver().query(contentUri, proj, null, null, null); if (cursor.moveToFirst()) { int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); res = cursor.getString(column_index); yourSelectedImage = BitmapFactory.decodeFile(res); } cursor.close(); return res; }
Step 7- Defined here application manifest.xml file
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.customkeyboard"> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission> <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" android:label="@string/app_name" android:theme="@style/AppTheme.NoActionBar" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".MyKeyboardService" 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> </application> </manifest>
Step 8- Set your custom keyboard as default keyboard
First, open device settings files then select Language & Input option, select Current Keyboard option and finally choose MyCustomKeyboard options.
settings -> Language & Input -> Current Keyboard -> MyCustomKeyboard
Now your custom keyboard will work as default keyboard.
Note:- We have attached application screen shot. You can also get complete source code from attachment.
0 Comment(s)