一、 Android 自定義軟鍵盤開發(fā)流程
- 建立軟鍵盤樣式
? ? ? ?即在項(xiàng)目res文件夾中創(chuàng)建所需要的各種軟鍵盤的樣式(比如說:字母、數(shù)字蹬耘、符號(hào) 等)欺嗤。 - 創(chuàng)建layout布局文件(非必須)
? ? ? ?在布局文件中給軟鍵盤創(chuàng)建container,以便顯示軟鍵盤 - 自定義KeyboardView
? ? ? ?自定義一個(gè)KeyboardView 并繼承自KeyboardView累驮,在自定義的KeyboardView中繪制特殊按鍵酣倾,包括按鍵的點(diǎn)擊背景,圖片谤专,文字 等躁锡。 - 自定義一個(gè)普通java類,一般取名為 **Keyboard.java
? ? ? ?把軟鍵盤加載到container中毒租,即在布局文件里預(yù)留的存放軟鍵盤 的container稚铣。
? ? ? ?在類的內(nèi)部實(shí)現(xiàn)軟鍵盤的輸入控制箱叁,鍵盤轉(zhuǎn)換控制,軟鍵盤的顯示與隱藏控制 等惕医。
? ? ? ?在需要用到軟鍵盤的Activity中實(shí)例化該Keyboard 類耕漱,并傳入必要的數(shù)據(jù)和信息。
二抬伺、建立軟鍵盤樣式
? ? ? ?建立軟鍵盤樣式可以直接通過xml進(jìn)行排版螟够,在res/xml中創(chuàng)建一個(gè)根節(jié)點(diǎn)為Keyboard的xml就可以開始排版了
這個(gè)xml中屬性如下:
Keyboard.Key 屬性 | 介紹 |
---|---|
android:codes | 此鍵輸出的unicode值或逗號(hào)分隔值。 |
android:horizontalGap | 鍵之間的默認(rèn)水平間隙峡钓。 |
android:iconPreview | 彈出預(yù)覽中顯示的圖標(biāo)妓笙。 |
android:isModifier | 這是否是修改鍵,如Alt或Shift能岩。 |
android:isRepeatable | 是否長按此鍵會(huì)使其重復(fù)寞宫。 |
android:isSticky | 這是否是切換鍵。 |
android:keyEdgeFlags | 關(guān)鍵邊緣標(biāo)志拉鹃。 |
android:keyHeight | 鍵的默認(rèn)高度辈赋,以像素為單位或顯示寬度的百分比。 |
android:keyIcon | 要在鍵上顯示的圖標(biāo)而不是標(biāo)簽膏燕。 |
android:keyLabel | 要在鍵上顯示的標(biāo)簽钥屈。 |
android:keyOutputText | 按下此鍵時(shí)要輸出的字符串。 |
android:keyWidth | 鍵的默認(rèn)寬度坝辫,以像素為單位或顯示寬度的百分比篷就。 |
android:popupCharacters | 要在彈出鍵盤中顯示的字符。 |
android:popupKeyboard | 任何彈出鍵盤的XML鍵盤布局近忙。 |
實(shí)例代碼:
數(shù)字鍵盤
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="2.5%p"
android:keyHeight="6%p"
android:keyWidth="30%p"
android:verticalGap="10px">
<Row>
<Key android:codes="49" android:keyLabel="1" />
<Key android:codes="50" android:keyLabel="2" />
<Key android:codes="51" android:keyLabel="3" />
</Row>
<Row>
<Key android:codes="52" android:keyLabel="4" />
<Key android:codes="53" android:keyLabel="5" />
<Key android:codes="54" android:keyLabel="6" />
</Row>
<Row>
<Key android:codes="55" android:keyLabel="7" />
<Key android:codes="56" android:keyLabel="8" />
<Key android:codes="57" android:keyLabel="9" />
</Row>
<Row>
<Key android:codes="-2" android:keyLabel="ABC" />
<Key android:codes="48" android:keyLabel="0" />
<Key android:codes="-35" android:isRepeatable="true" />
</Row>
</Keyboard>
英文鍵盤:
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="1%p"
android:keyHeight="6%p"
android:keyWidth="10%p"
android:verticalGap="10px">
<Row>
<Key android:codes="113" android:keyEdgeFlags="left" android:keyLabel="q" android:keyWidth="8.9%p" />
<Key android:codes="119" android:keyLabel="w" android:keyWidth="8.9%p" />
<Key android:codes="101" android:keyLabel="e" android:keyWidth="8.9%p" />
<Key android:codes="114" android:keyLabel="r" android:keyWidth="8.9%p" />
<Key android:codes="116" android:keyLabel="t" android:keyWidth="8.9%p" />
<Key android:codes="121" android:keyLabel="y" android:keyWidth="8.9%p" />
<Key android:codes="117" android:keyLabel="u" android:keyWidth="8.9%p" />
<Key android:codes="105" android:keyLabel="i" android:keyWidth="8.9%p" />
<Key android:codes="111" android:keyLabel="o" android:keyWidth="8.9%p" />
<Key android:codes="112" android:keyEdgeFlags="right" android:keyLabel="p" android:keyWidth="8.9%p" />
</Row>
<Row>
<Key android:codes="97" android:horizontalGap="5.5%p" android:keyEdgeFlags="left" android:keyLabel="a" android:keyWidth="9%p" />
<Key android:codes="115" android:keyLabel="s" android:keyWidth="9%p" />
<Key android:codes="100" android:keyLabel="d" android:keyWidth="9%p" />
<Key android:codes="102" android:keyLabel="f" android:keyWidth="9%p" />
<Key android:codes="103" android:keyLabel="g" android:keyWidth="9%p" />
<Key android:codes="104" android:keyLabel="h" android:keyWidth="9%p" />
<Key android:codes="106" android:keyLabel="j" android:keyWidth="9%p" />
<Key android:codes="107" android:keyLabel="k" android:keyWidth="9%p" />
<Key android:codes="108" android:keyEdgeFlags="right" android:keyLabel="l" android:keyWidth="9%p" />
</Row>
<Row>
<Key android:codes="-1" android:isModifier="true" android:isSticky="true" android:keyEdgeFlags="left" android:keyWidth="13%p" />
<Key android:codes="122" android:horizontalGap="1.5%p" android:keyLabel="z" android:keyWidth="9%p" />
<Key android:codes="120" android:keyLabel="x" android:keyWidth="9%p" />
<Key android:codes="99" android:keyLabel="c" android:keyWidth="9%p" />
<Key android:codes="118" android:keyLabel="v" android:keyWidth="9%p" />
<Key android:codes="98" android:keyLabel="b" android:keyWidth="9%p" />
<Key android:codes="110" android:keyLabel="n" android:keyWidth="9%p" />
<Key android:codes="109" android:keyLabel="m" android:keyWidth="9%p" />
<Key android:codes="-5" android:horizontalGap="1.5%p" android:isRepeatable="true" android:keyWidth="13%p" />
</Row>
<Row android:rowEdgeFlags="bottom">
<Key android:codes="-2" android:keyLabel="123" android:keyWidth="19%p" />
<Key android:codes="32" android:isRepeatable="false" android:keyLabel="space" android:keyWidth="58%p" />
<Key android:codes="100860" android:keyEdgeFlags="right" android:keyLabel="#+=" android:keyWidth="19%p" />
</Row>
</Keyboard>
三竭业、自定義KeyboardView
? ? ? ?如果你對KeyboardView的按鍵有特定的一些樣式的話,那你就要自定義KeyboardView了银锻。
? ? ? ?自定義KeyboardView最重要的就是重寫onDraw方法永品,同時(shí)注意一定要寫繪制背景再繪制文本。List<Keyboard.Key> keys = getKeyboard().getKeys();
這個(gè)是獲取所有按鍵信息Keyboard.Key
击纬,其中Key.codes
是獲取xml中設(shè)定的code鼎姐,可以根據(jù)這個(gè)判定需要繪制的樣式不同。
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.support.annotation.DrawableRes;
import android.util.AttributeSet;
import java.lang.reflect.Field;
import java.util.List;
public class CustomKeyboardView extends KeyboardView {
private Context context;
private Paint paint;
private Rect bounds;
public CustomKeyboardView(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
paint.setTextAlign(Paint.Align.CENTER);
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
bounds = new Rect();
this.context = context;
}
public CustomKeyboardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint = new Paint();
paint.setTextAlign(Paint.Align.CENTER);
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
bounds = new Rect();
this.context = context;
}
/**
* 重寫這個(gè)方法是為了可以繪制一些特殊按鍵
* @param canvas
*/
@Override
public void onDraw(Canvas canvas) {
List<Keyboard.Key> keys = getKeyboard().getKeys();
for (Keyboard.Key key : keys) {
if(key.codes[0] != -5 && key.codes[0] != -4){
//繪制普通信息文本的背景
drawBackground(R.drawable.keyboard_bg,canvas,key);
//繪制普通信息的文本信息
drawText(canvas,key);
}else{
//繪制特殊按鍵
drawSpecialKey(canvas,key);
}
}
}
private void drawSpecialKey(Canvas canvas, Keyboard.Key key) {
if(key.codes[0] == -5){
drawBackground(R.drawable.keyboard_bg,canvas,key);
//繪制設(shè)置了icon的按鈕
key.icon.setBounds(key.x + (key.width - key.icon.getIntrinsicWidth()) / 2,
key.y + (key.height - key.icon.getIntrinsicHeight()) / 2,
key.x + (key.width - key.icon.getIntrinsicWidth()) / 2 + key.icon.getIntrinsicWidth(),
key.y + (key.height - key.icon.getIntrinsicHeight()) / 2 + key.icon.getIntrinsicHeight());
key.icon.draw(canvas);
}else if(key.codes[0] == -4){
drawBackground(R.drawable.white,canvas,key);
}
}
private void drawBackground(@DrawableRes int drawableId, Canvas canvas, Keyboard.Key key) {
Drawable drawable = context.getResources().getDrawable(drawableId);
int[] state = key.getCurrentDrawableState();
if (key.codes[0] != 0) {
drawable.setState(state);
}
drawable.setBounds(key.x, key.y, key.x + key.width, key.y + key.height);
drawable.draw(canvas);
}
//繪制文本
private void drawText(Canvas canvas, Keyboard.Key key) {
if(key.label != null){
String label = key.label.toString();
Field field;
int keyTextSize;
try {
//獲取KeyboardView設(shè)置的默認(rèn)文本字體大小
field = KeyboardView.class.getDeclaredField("mLabelTextSize");
field.setAccessible(true);
keyTextSize = (int) field.get(this);
paint.setTextSize(keyTextSize);
paint.setTypeface(Typeface.DEFAULT);
paint.getTextBounds(label,0,label.length(),bounds);
canvas.drawText(label,key.x + (key.width / 2), (key.y + key.height / 2) + bounds.height() / 2, paint);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
四更振、自定義一個(gè)KeyBoard的幫助類
這個(gè)類里面主要的作用是使用我們自定義的KeyboardView代替系統(tǒng)自帶的KeyboardView進(jìn)行展示炕桨,這里的話主要是需要在EditText獲取焦點(diǎn)時(shí)候講彈出軟鍵盤設(shè)定成自定義的。
import android.annotation.SuppressLint;
import android.content.Context;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.os.Build;
import android.text.Editable;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
public class KeyboardUtil {
private Context mContext;
private KeyboardView mKeyboardView;
private EditText mEditText;
@SuppressLint("ClickableViewAccessibility")
public KeyboardUtil(Context context, KeyboardView keyboardView, EditText editText) {
this.mContext = context;
this.mKeyboardView = keyboardView;
this.mEditText = editText;
initKeyboard();
mEditText.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
hideSystemKeyboard((EditText) v);
mKeyboardView.setVisibility(View.VISIBLE);
}
return false;
}
});
mEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (v instanceof EditText) {
if (!hasFocus) {
mKeyboardView.setVisibility(View.GONE);
} else {
hideSystemKeyboard((EditText) v);
mKeyboardView.setVisibility(View.VISIBLE);
}
}
}
});
}
private void hideSystemKeyboard(EditText v) {
this.mEditText = v;
InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
if(imm == null){
return;
}
boolean isOpen = imm.isActive();
if (isOpen) {
imm.hideSoftInputFromWindow(v.getWindowToken(),0);
}
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
v.setShowSoftInputOnFocus(false);
}else{
v.setInputType(0);
}
}
private void initKeyboard() {
Keyboard keyboard = new Keyboard(mContext,R.xml.number_keyboard);
mKeyboardView.setKeyboard(keyboard);
mKeyboardView.setEnabled(true);
mKeyboardView.setOnKeyboardActionListener(listener);
}
private KeyboardView.OnKeyboardActionListener listener = new KeyboardView.OnKeyboardActionListener() {
@Override
public void onPress(int primaryCode) {
if(primaryCode == -4 || primaryCode == -5){
mKeyboardView.setPreviewEnabled(false);
}else{
mKeyboardView.setPreviewEnabled(true);
}
}
@Override
public void onRelease(int primaryCode) {
}
@Override
public void onKey(int primaryCode, int[] keyCodes) {
Editable editable = mEditText.getText();
int start = mEditText.getSelectionStart();
int end = mEditText.getSelectionEnd();
if(primaryCode == Keyboard.KEYCODE_DONE){
mKeyboardView.setVisibility(View.GONE);
}else if(primaryCode == Keyboard.KEYCODE_DELETE){
if(editable != null && editable.length() > 0){
if(start == end){
editable.delete(start -1, start);
}else{
editable.delete(start,end);
}
}
}else{
editable.replace(start,end,Character.toString((char) primaryCode));
}
}
@Override
public void onText(CharSequence text) {
}
@Override
public void swipeLeft() {
}
@Override
public void swipeRight() {
}
@Override
public void swipeDown() {
}
@Override
public void swipeUp() {
}
};
}
以上就是自定義軟件盤所有相關(guān)的操作肯腕,這個(gè)是比較簡單的献宫,如果要負(fù)責(zé)的話,就需要多研究下实撒,如果有啥沒寫好的姊途,見諒一下涉瘾,第一次寫。