以前知道有個KeyboardView這個東西可以自定義鍵盤,但因爲一直沒涉及到,所以沒研究過,今天看到工商銀行密碼輸入的鍵盤覺得挺好看,就來研究一下。
先看一下工商銀行的圖
下邊是我的效果圖
參考了:http://blog.csdn.net/hfsu0419/article/details/7924673
http://www.cnblogs.com/jason-star/archive/2012/12/15/2819174.html
兩篇博客。
現在做一下筆記。
在需要顯示鍵盤的佈局中,插入這部分代碼
android:keyBackground代表按鍵的背景
android:keyPreviewHeight按下後預覽字符的高度
android:keyPreviewLayout按下後預覽字符的佈局(有默認的)
android:keyPreviewOffset偏移量,調整預覽時顯示的位置
<RelativeLayout
android:id="@+id/rl_keyboard"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="gone">
<!--
沒有這兩個屬性,按鍵上文字會發虛模糊
android:shadowColor="#FFFFFF"
android:shadowRadius="0.0"-->
<android.inputmethodservice.KeyboardView
android:id="@+id/keyboard_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#ECECEC"
android:focusable="true"
android:focusableInTouchMode="true"
android:keyBackground="@drawable/btn_keyboard_key"
android:keyPreviewHeight="100dp"
android:keyPreviewLayout="@layout/key_preview_layout"
android:keyPreviewOffset="50dp"
android:keyTextColor="#4F4F4F"
android:paddingBottom="5dp"
android:paddingTop="5dp"
android:shadowColor="#FFFFFF"
android:shadowRadius="0.0" />
</RelativeLayout>
通過Keyboard說明是一個軟鍵盤定義文件,Row元素說明這是一行按鍵的定義,Key元素說明這是一個按鍵的定義。Key元素通過一些屬性來定義每個按鍵,下面是一些常用的屬性介紹:
Codes:代表按鍵對應的輸出值,可以爲unicode值或則逗號(,)分割的多個值,也可以爲一個字 符串。在字符串中通過“\”來轉義特殊字符,例如 ‘\n’ 或則 ‘\uxxxx’ 。Codes通常用來定義該鍵的鍵碼,例如上圖中的數字按鍵1對應的爲49;如果提供的是逗號分割的多個值則和普通手機輸入鍵盤一樣在多個值之間切換。
keyLabel:代表按鍵顯示的文本內容。
keyIcon:代表按鍵顯示的圖標內容,如果指定了該值則在顯示的時候顯示爲圖片不顯示文本。
keyWidth:代表按鍵的寬度,可以爲精確值或則相對值,對於精確值支持多種單位,例如:像素,英寸 等;相對值爲相對於基礎取值的百分比,爲以% 或則%p 結尾,其中%p表示相對於父容器。
keyHeight:代表按鍵的高度,取值同上。
horizontalGap:代表按鍵前的間隙(水平方向),取值同上。
isSticky:指定按鍵是否爲sticky的。例如Shift大小寫切換按鍵,具有兩種狀態,按下狀態和正常狀態,取值爲true或則false。
isModifier:指定按鍵是否爲功能鍵( modifier key ) ,例如 Alt 或則 Shift 。取值爲true或則false。
keyOutputText:指定按鍵輸出的文本內容,取值爲字符串。
isRepeatable:指定按鍵是否是可重複的,如果長按該鍵可以觸發重複按鍵事件則爲true,否則爲false。
keyEdgeFlags:指定按鍵的對齊指令,取值爲left或則right。
首先在res下建xml文件夾,在文件夾下建字母,數字,符號三個xml文件。
字母鍵盤qwerty.xml
<?xml version="1.0" encoding="UTF-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="0.0px"
android:keyHeight="@dimen/key_height"
android:keyWidth="10.000002%p"
android:verticalGap="0.0px">
<Row>
<Key
android:codes="113"
android:keyEdgeFlags="left"
android:keyLabel="q" />
<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:keyEdgeFlags="right"
android:keyLabel="p" />
</Row>
<Row>
<Key
android:codes="97"
android:horizontalGap="4.999995%p"
android:keyEdgeFlags="left"
android:keyLabel="a" />
<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:keyEdgeFlags="right"
android:keyLabel="l" />
</Row>
<Row>
<Key
android:codes="-1"
android:isModifier="true"
android:isSticky="true"
android:keyEdgeFlags="left"
android:keyIcon="@drawable/sym_keyboard_shift_normal"
android:keyWidth="14.999998%p" />
<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:isRepeatable="true"
android:keyEdgeFlags="right"
android:keyIcon="@drawable/sym_keyboard_delete"
android:keyWidth="14.999998%p" />
</Row>
<Row android:rowEdgeFlags="bottom">
<!--
isSticky:指定按鍵是否爲sticky的。例如Shift大小寫切換按鍵,具有兩種狀態,按下狀態和正常狀態,取值爲true或則false。
isModifier:指定按鍵是否爲功能鍵( modifier key ) ,例如 Alt 或則 Shift 。取值爲true或則false。-->
<Key
android:codes="32"
android:isModifier="true"
android:isRepeatable="true"
android:keyEdgeFlags="left"
android:keyLabel="小侯子安全鍵盤"
android:keyWidth="74.999996%p" />
<Key
android:codes="-4"
android:keyEdgeFlags="right"
android:keyLabel="完成"
android:keyWidth="25.000004%p" />
</Row>
</Keyboard>
數字鍵盤digit.xml
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="0px"
android:keyHeight="@dimen/key_height"
android:keyWidth="33%p"
android:verticalGap="0px">
<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="-5"
android:keyIcon="@drawable/sym_keyboard_delete" />
</Row>
<Row>
<Key
android:codes="57"
android:keyLabel="9" />
<Key
android:codes="48"
android:keyLabel="0" />
<Key
android:codes="-4"
android:isRepeatable="true"
android:keyEdgeFlags="right"
android:keyLabel="完成" />
</Row>
</Keyboard>
符號鍵盤symbol.xml
<?xml version="1.0" encoding="UTF-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="0.0px"
android:keyHeight="@dimen/key_height"
android:keyWidth="10.000002%p"
android:verticalGap="0.0px">
<Row>
<Key
android:codes="91"
android:keyEdgeFlags="left"
android:keyLabel="[" />
<Key
android:codes="93"
android:keyLabel="]" />
<Key
android:codes="123"
android:keyLabel="{" />
<Key
android:codes="125"
android:keyLabel="}" />
<Key
android:codes="35"
android:keyLabel="#" />
<Key
android:codes="37"
android:keyLabel="%" />
<Key
android:codes="94"
android:keyLabel="^" />
<Key
android:codes="42"
android:keyLabel="*" />
<Key
android:codes="43"
android:keyLabel="+" />
<Key
android:codes="61"
android:keyEdgeFlags="right"
android:keyLabel="=" />
</Row>
<Row>
<Key
android:codes="95"
android:keyEdgeFlags="left"
android:keyLabel="_" />
<Key
android:codes="45"
android:keyLabel="-" />
<Key
android:codes="47"
android:keyLabel="/" />
<Key
android:codes="58"
android:keyLabel=":" />
<Key
android:codes="59"
android:keyLabel=";" />
<Key
android:codes="40"
android:keyLabel="(" />
<Key
android:codes="41"
android:keyLabel=")" />
<Key
android:codes="36"
android:keyLabel="$" />
<!--&-->
<Key
android:codes="38"
android:keyLabel="&" />
<Key
android:codes="64"
android:keyLabel="\@" />
</Row>
<Row>
<Key
android:codes="46"
android:keyEdgeFlags="left"
android:keyLabel="." />
<Key
android:codes="44"
android:keyEdgeFlags="right"
android:keyLabel="," />
<Key
android:codes="63"
android:keyLabel="\?" />
<Key
android:codes="33"
android:keyLabel="!" />
<Key
android:codes="39"
android:keyLabel="'" />
<!--\-->
<Key
android:codes="92"
android:keyLabel="\\" />
<Key
android:codes="124"
android:keyLabel="|" />
<Key
android:codes="126"
android:keyLabel="~" />
<Key
android:codes="-5"
android:isRepeatable="true"
android:keyEdgeFlags="right"
android:keyIcon="@drawable/sym_keyboard_delete"
android:keyWidth="20.000004%p" />
</Row>
<Row android:rowEdgeFlags="bottom">
<Key
android:codes="96"
android:keyLabel="`" />
<!--<-->
<Key
android:codes="60"
android:keyLabel="<" />
<!-->-->
<Key
android:codes="62"
android:keyLabel=">" />
<Key
android:codes="8364"
android:keyLabel="€" />
<Key
android:codes="163"
android:keyLabel="£" />
<Key
android:codes="165"
android:keyLabel="¥" />
<!--"-->
<Key
android:codes="34"
android:keyLabel=""" />
<Key
android:codes="-4"
android:keyEdgeFlags="right"
android:keyLabel="完成"
android:keyWidth="30.000006%p" />
</Row>
</Keyboard>
有的符號在xml中不能直接寫,可以用ASCII編碼代替
k1 = new Keyboard(ctx, R.xml.qwerty);
k2 = new Keyboard(ctx, R.xml.digit);
k3 = new Keyboard(ctx, R.xml.symbol);
keyboardView = (KeyboardView) act.findViewById(R.id.keyboard_view);
rlKeyboard = (RelativeLayout) act.findViewById(R.id.rl_keyboard);
keyboardView.setKeyboard(k1);//顯示那個就set哪個
keyboardView.setEnabled(true);
keyboardView.setPreviewEnabled(true);//可預覽
keyboardView.setOnKeyboardActionListener(listener);
在onKey方法中做處理
private OnKeyboardActionListener listener = new OnKeyboardActionListener() {
...
@Override
public void onKey(int primaryCode, int[] keyCodes) {
Editable editable = ed.getText();
int start = ed.getSelectionStart();
if (primaryCode == Keyboard.KEYCODE_DONE) {// 完成
hideKeyboard();
} else if (primaryCode == Keyboard.KEYCODE_DELETE) {// 回退
if (editable != null && editable.length() > 0) {
if (start > 0) {
editable.delete(start - 1, start);
}
}
} else if (primaryCode == Keyboard.KEYCODE_SHIFT) {// 大小寫切換
changeKey();
keyboardView.setKeyboard(k1);
} else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {// 數字鍵盤切換
if (isnun) {
isnun = false;
keyboardView.setKeyboard(k1);
} else {
isnun = true;
randomdigkey();//數字做了隨機,每次位置不同
keyboardView.setKeyboard(k2);
}
} else if (primaryCode == 57419) { // go left
if (start > 0) {
ed.setSelection(start - 1);
}
} else if (primaryCode == 57421) { // go right
if (start < ed.length()) {
ed.setSelection(start + 1);
}
} else {
editable.insert(start, Character.toString((char) primaryCode));
}
}
};
KeyboardUtil.java完整代碼
package com.juxin.common.utils;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.Keyboard.Key;
import android.inputmethodservice.KeyboardView;
import android.inputmethodservice.KeyboardView.OnKeyboardActionListener;
import android.media.AudioAttributes;
import android.os.Vibrator;
import android.provider.Settings;
import android.text.Editable;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.juxin.common.R;
import com.juxin.common.widget.SafeEditText;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
public class KeyboardUtil {
private Context ctx;
private Activity act;
private KeyboardView keyboardView;
private Keyboard k1;// 字母鍵盤
private Keyboard k2;// 數字鍵盤
private Keyboard k3;// 符號鍵盤
public boolean isnun = false;// 是否數據鍵盤
public boolean isupper = false;// 是否大寫
private Resources resources;
private EditText ed;
private RelativeLayout rlKeyboard;
private TextView tvSystemKeyboard;
private RadioGroup rgChangeKeyboard;
private RadioButton rbDigit, rbLetter, rbSymbol;
public KeyboardUtil(Activity act, Context ctx, EditText edit) {
this.act = act;
this.ctx = ctx;
this.ed = edit;
resources = ctx.getResources();
k1 = new Keyboard(ctx, R.xml.qwerty);
k2 = new Keyboard(ctx, R.xml.digit);
k3 = new Keyboard(ctx, R.xml.symbol);
keyboardView = (KeyboardView) act.findViewById(R.id.keyboard_view);
rlKeyboard = (RelativeLayout) act.findViewById(R.id.rl_keyboard);
keyboardView.setKeyboard(k1);
keyboardView.setEnabled(true);
keyboardView.setPreviewEnabled(true);
keyboardView.setOnKeyboardActionListener(listener);
rgChangeKeyboard = (RadioGroup) act.findViewById(R.id.rgChangeKeyboard);
tvSystemKeyboard = (TextView) act.findViewById(R.id.tvSystemKeyboard);
rbDigit = (RadioButton) act.findViewById(R.id.rb_digit);
rbLetter = (RadioButton) act.findViewById(R.id.rb_letter);
rbSymbol = (RadioButton) act.findViewById(R.id.rb_symbol);
tvSystemKeyboard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openKeyBoard();
}
});
rgChangeKeyboard.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (checkedId == R.id.rb_digit) {
isnun = true;
randomdigkey();
keyboardView.setKeyboard(k2);
} else if (checkedId == R.id.rb_letter) {
isnun = false;
keyboardView.setKeyboard(k1);
} else if (checkedId == R.id.rb_symbol) {
keyboardView.setKeyboard(k3);
}
}
});
}
private OnKeyboardActionListener listener = new OnKeyboardActionListener() {
@Override
public void swipeUp() {
}
@Override
public void swipeRight() {
}
@Override
public void swipeLeft() {
}
@Override
public void swipeDown() {
}
@Override
public void onText(CharSequence text) {
}
@Override
public void onRelease(int primaryCode) {
}
@Override
public void onPress(int primaryCode) {
vibrate(20);
if (primaryCode == Keyboard.KEYCODE_SHIFT || primaryCode == Keyboard.KEYCODE_DELETE
|| primaryCode == Keyboard.KEYCODE_DONE || primaryCode == 32 || primaryCode == Keyboard.KEYCODE_MODE_CHANGE
|| (primaryCode >= 48 && primaryCode <= 57)) {
keyboardView.setPreviewEnabled(false);
} else {
keyboardView.setPreviewEnabled(true);
}
}
@Override
public void onKey(int primaryCode, int[] keyCodes) {
Editable editable = ed.getText();
int start = ed.getSelectionStart();
if (primaryCode == Keyboard.KEYCODE_DONE) {// 完成
hideKeyboard();
} else if (primaryCode == Keyboard.KEYCODE_DELETE) {// 回退
if (editable != null && editable.length() > 0) {
if (start > 0) {
editable.delete(start - 1, start);
}
}
} else if (primaryCode == Keyboard.KEYCODE_SHIFT) {// 大小寫切換
changeKey();
keyboardView.setKeyboard(k1);
} else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {// 數字鍵盤切換
if (isnun) {
isnun = false;
keyboardView.setKeyboard(k1);
} else {
isnun = true;
randomdigkey();
keyboardView.setKeyboard(k2);
}
} else {
editable.insert(start, Character.toString((char) primaryCode));
}
}
};
private void randomdigkey() {
List<Key> keyList = k2.getKeys();
// 查找出0-9的數字鍵
List<Key> newkeyList = new ArrayList<Key>();
for (int i = 0; i < keyList.size(); i++) {
if (keyList.get(i).label != null
&& isNumber(keyList.get(i).label.toString())) {
newkeyList.add(keyList.get(i));
}
}
// 數組長度
int count = newkeyList.size();
// 結果集
List<KeyModel> resultList = new ArrayList<KeyModel>();
// 用一個LinkedList作爲中介
LinkedList<KeyModel> temp = new LinkedList<KeyModel>();
// 初始化temp
for (int i = 0; i < count; i++) {
temp.add(new KeyModel(48 + i, i + ""));
}
// 取數
Random rand = new Random();
for (int i = 0; i < count; i++) {
int num = rand.nextInt(count - i);
resultList.add(new KeyModel(temp.get(num).getCode(), temp.get(num)
.getLable()));
temp.remove(num);
}
for (int i = 0; i < newkeyList.size(); i++) {
newkeyList.get(i).label = resultList.get(i).getLable();
newkeyList.get(i).codes[0] = resultList.get(i).getCode();
}
keyboardView.setKeyboard(k2);
}
private boolean isNumber(String str) {
String wordstr = "0123456789.,";
if (wordstr.indexOf(str) > -1) {
return true;
}
return false;
}
/**
* 鍵盤大小寫切換
*/
private void changeKey() {
List<Key> keylist = k1.getKeys();
if (isupper) {// 大寫切換小寫
isupper = false;
for (Key key : keylist) {
if (key.label != null && isword(key.label.toString())) {
key.label = key.label.toString().toLowerCase();
key.codes[0] = key.codes[0] + 32;
} else if (key.sticky && key.codes[0] == Keyboard.KEYCODE_SHIFT) {
key.icon = resources.getDrawable(R.drawable.sym_keyboard_shift_normal);
}
}
} else {// 小寫切換大寫
isupper = true;
for (Key key : keylist) {
if (key.label != null && isword(key.label.toString())) {
key.label = key.label.toString().toUpperCase();
key.codes[0] = key.codes[0] - 32;
} else if (key.sticky && key.codes[0] == Keyboard.KEYCODE_SHIFT) {
key.icon = resources.getDrawable(R.drawable.sym_keyboard_shift_press);
}
}
}
}
public void showKeyboard() {
hideKeyBoard();
if (this.ed instanceof SafeEditText) {
Settings.System.putInt(this.act.getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD, 0);
} else {
Settings.System.putInt(this.act.getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD, 1);
}
rbLetter.setChecked(true);
int visibility = rlKeyboard.getVisibility();
if (visibility == View.GONE || visibility == View.INVISIBLE) {
rlKeyboard.setVisibility(View.VISIBLE);
rlKeyboard.startAnimation(AnimationUtils.loadAnimation(this.act, R.anim.show_keyboard));
}
}
public void hideKeyboard() {
Settings.System.putInt(this.act.getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD, 1);
int visibility = rlKeyboard.getVisibility();
if (visibility == View.VISIBLE) {
rlKeyboard.setVisibility(View.INVISIBLE);
rlKeyboard.startAnimation(AnimationUtils.loadAnimation(this.act, R.anim.hide_keyboard));
}
}
private boolean isword(String str) {
String wordstr = "abcdefghijklmnopqrstuvwxyz";
if (wordstr.indexOf(str.toLowerCase()) > -1) {
return true;
}
return false;
}
/**
* 打開軟鍵盤
*/
protected void openKeyBoard() {
hideKeyboard();
InputMethodManager imm = (InputMethodManager) this.ctx.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
}
/**
* 關閉軟鍵盤
*/
protected void hideKeyBoard() {
InputMethodManager inputMsg = (InputMethodManager) this.ctx.getSystemService(Context.INPUT_METHOD_SERVICE);
if (inputMsg.isActive()) { // 隱藏軟鍵盤
View curView = this.act.getCurrentFocus();
if (curView != null) {
inputMsg.hideSoftInputFromWindow(curView.getWindowToken(), 0);
}
}
}
/**
* 震動
*
* @param duration
*/
protected void vibrate(long duration) {
Vibrator vibrator = (Vibrator) this.act.getSystemService(Context.VIBRATOR_SERVICE);
long[] pattern = {
0, duration
};
vibrator.vibrate(pattern, -1);
}
}
在activity中的使用:
edit = (EditText) this.findViewById(R.id.edit);
edit.setInputType(InputType.TYPE_NULL);
edit1 =(SafeEditText)this.findViewById(R.id.edit1);
edit.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int inputback = edit.getInputType();
new KeyboardUtil(act, ctx, edit).showKeyboard();
edit.setInputType(inputback);
return false;
}
});
edit1.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
edit1.setText("");
int inputback = edit1.getInputType();
edit1.setInputType(InputType.TYPE_NULL);
new KeyboardUtil(act, ctx, edit1).showKeyboard();
edit1.setInputType(inputback);
return false;
}
});
// keyWidth的寬度超過50%時,點擊左右兩邊位置不起作用,是因爲getNearestKeys方法裏通過座標計算問題,重寫Keyboard的getNearestKeys方法可解決。(看這裏)
@Override
public int[] getNearestKeys(int x, int y) {
List<Key> keys = getKeys();
Key[] mKeys = keys.toArray(new Key[keys.size()]);
int i = 0;
for (Key key : mKeys) {
if(key.isInside(x, y)) {
return new int[]{i};
}
i++;
}
return new int[0];
}