最近项目中有使用到自定义的键盘,就是那种特殊的键盘,是一款输入车牌的键盘,效果图如下:
完成以上效果我想到有两种实现方式:
第一种就是自定义键盘,主要用到的就是Keyboard和KeyboardView两个类.这种方式的话我觉得不好的一点就是需要edittext才能唤醒键盘.
第二种就是自定义两个pupopwindow或者dialog都行,这种就是在popupwindow中把按钮当成一个一个button摆好都添加点击事件,点击之后回调出点击的那个按钮的gettext()方法拿到值,对于删除键就是特殊的值和处理方式就好.这种方式的话给我的感觉不好之处就是太多初始化和点击的监听了.
我先说第一种实现步骤:
1.在工程的res目录下创建xml文件夹,然后创建两个文件,一个是放省份的键盘数据源和样式province_abbreviation.xml,一个是放数字和大写字母的键盘数据源和样式number_or_letters.xml.(注意根标签是Keyboard)
这里讲解一下各个标签的作用
根目录一定是Keyboard里面可以设置每个键的宽和高通过keyHeight和keyWidth来改变取值为(10%p)当每个key中设置了该值时以key中的大小为准.
往下是Row标签 一个row标签代表一行.
在往下是Key标签 里面就代表着一个一个的按键了,包裹在Row标签中,比如一行需要10个按键时就放10个key标签,keyLabel属性代表的是文本该展示什么字,codes代表的是一个assiic码表中对应的值.比如说49,50意思就是按第一下按钮时是1按第二下按钮为2.
以下贴出xml中的代码:
province_abbreviation文件中的代码:
<?xml version="1.0" encoding="UTF-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="0.0px"
android:keyHeight="8%p"
android:keyWidth="10%p"
android:verticalGap="0.0px">
<Row android:verticalGap="1%p">
<Key
android:codes="20140"
android:horizontalGap="1%p"
android:keyEdgeFlags="left"
android:keyLabel="京"
android:keyWidth="8%p" />
<Key
android:codes="27818"
android:horizontalGap="2%p"
android:keyLabel="沪"
android:keyWidth="8%p" />
<Key
android:codes="31908"
android:horizontalGap="2%p"
android:keyLabel="粤"
android:keyWidth="8%p"
/>
<Key
android:codes="27941"
android:horizontalGap="2%p"
android:keyLabel="津"
android:keyWidth="8%p"
/>
<Key
android:codes="20864"
android:horizontalGap="2%p"
android:keyLabel="冀"
android:keyWidth="8%p"
/>
<Key
android:codes="26187"
android:horizontalGap="2%p"
android:keyLabel="晋"
android:keyWidth="8%p"
/>
<Key
android:codes="33945"
android:horizontalGap="2%p"
android:keyLabel="蒙"
android:keyWidth="8%p" />
<Key
android:codes="36797"
android:horizontalGap="2%p"
android:keyLabel="辽"
android:keyWidth="8%p"
/>
<Key
android:codes="21513"
android:horizontalGap="2%p"
android:keyLabel="吉"
android:keyWidth="8%p"
/>
<Key
android:codes="40657"
android:horizontalGap="2%p"
android:keyEdgeFlags="right"
android:keyLabel="黑"
android:keyWidth="8%p" />
</Row>
<Row android:verticalGap="1%p">
<Key
android:codes="33487"
android:horizontalGap="6.5%p"
android:keyEdgeFlags="left"
android:keyLabel="苏"
android:keyWidth="8%p" />
<Key
android:codes="27993"
android:horizontalGap="2%p"
android:keyLabel="浙"
android:keyWidth="8%p" />
<Key
android:codes="30358"
android:horizontalGap="2%p"
android:keyLabel="皖"
android:keyWidth="8%p" />
<Key
android:codes="38397"
android:horizontalGap="2%p"
android:keyLabel="闽"
android:keyWidth="8%p" />
<Key
android:codes="36195"
android:horizontalGap="2%p"
android:keyLabel="赣"
android:keyWidth="8%p" />
<Key
android:codes="40065"
android:horizontalGap="2%p"
android:keyLabel="鲁"
android:keyWidth="8%p" />
<Key
android:codes="35947"
android:horizontalGap="2%p"
android:keyLabel="豫"
android:keyWidth="8%p" />
<Key
android:codes="37122"
android:horizontalGap="2%p"
android:keyLabel="鄂"
android:keyWidth="8%p" />
<Key
android:codes="28248"
android:horizontalGap="2%p"
android:keyLabel="湘"
android:keyWidth="8%p" />
</Row>
<Row android:verticalGap="1%p">
<Key
android:codes="26690"
android:horizontalGap="11%p"
android:keyEdgeFlags="right"
android:keyLabel="桂"
android:keyWidth="8%p" />
<Key
android:codes="29756"
android:horizontalGap="2%p"
android:keyLabel="琼"
android:keyWidth="8%p" />
<Key
android:codes="28189"
android:horizontalGap="2%p"
android:keyEdgeFlags="left"
android:keyLabel="渝"
android:keyWidth="8%p" />
<Key
android:codes="24029"
android:horizontalGap="2%p"
android:keyLabel="川"
android:keyWidth="8%p" />
<Key
android:codes="36149"
android:horizontalGap="2%p"
android:keyLabel="贵"
android:keyWidth="8%p" />
<Key
android:codes="20113"
android:horizontalGap="2%p"
android:keyLabel="云"
android:keyWidth="8%p" />
<Key
android:codes="34255"
android:horizontalGap="2%p"
android:keyLabel="藏"
android:keyWidth="8%p" />
<Key
android:codes="38485"
android:horizontalGap="2%p"
android:keyLabel="陕"
android:keyWidth="8%p" />
</Row>
<Row>
<Key
android:codes="29976"
android:horizontalGap="26%p"
android:keyLabel="甘"
android:keyWidth="8%p" />
<Key
android:codes="38738"
android:horizontalGap="2%p"
android:keyEdgeFlags="right"
android:keyLabel="青"
android:keyWidth="8%p" />
<Key
android:codes="23425"
android:horizontalGap="2%p"
android:keyLabel="宁"
android:keyWidth="8%p" />
<Key
android:codes="26032"
android:horizontalGap="2%p"
android:keyLabel="新"
android:keyWidth="8%p" />
<Key
android:codes="20351"
android:horizontalGap="2%p"
android:keyLabel="使"
android:keyWidth="8%p" />
<Key
android:codes="-3"
android:keyIcon="@mipmap/icon_delete"
android:horizontalGap="2%p"
android:isRepeatable="false"
android:keyEdgeFlags="right"
android:keyWidth="15%p" />
</Row>
</Keyboard>
number_or_letters中的代码:
<?xml version="1.0" encoding="UTF-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="20.0px"
android:keyHeight="8%"
android:keyWidth="10%p"
android:verticalGap="50.0px">
<Row android:verticalGap="1%p">
<Key
android:codes="49"
android:horizontalGap="1%p"
android:keyEdgeFlags="left"
android:keyLabel="1"
android:keyWidth="8%p" />
<Key
android:codes="50"
android:horizontalGap="2%p"
android:keyLabel="2"
android:keyWidth="8%p" />
<Key
android:codes="51"
android:horizontalGap="2%p"
android:keyLabel="3"
android:keyWidth="8%p" />
<Key
android:codes="52"
android:horizontalGap="2%p"
android:keyLabel="4"
android:keyWidth="8%p" />
<Key
android:codes="53"
android:horizontalGap="2%p"
android:keyLabel="5"
android:keyWidth="8%p" />
<Key
android:codes="54"
android:horizontalGap="2%p"
android:keyLabel="6"
android:keyWidth="8%p" />
<Key
android:codes="55"
android:horizontalGap="2%p"
android:keyLabel="7"
android:keyWidth="8%p" />
<Key
android:codes="56"
android:horizontalGap="2%p"
android:keyLabel="8"
android:keyWidth="8%p" />
<Key
android:codes="57"
android:horizontalGap="2%p"
android:keyLabel="9"
android:keyWidth="8%p" />
<Key
android:codes="48"
android:horizontalGap="2%p"
android:keyEdgeFlags="right"
android:keyLabel="0"
android:keyWidth="8%p" />
</Row>
<Row android:verticalGap="1%p">
<Key
android:codes="65"
android:horizontalGap="1%p"
android:keyEdgeFlags="left"
android:keyLabel="A"
android:keyWidth="8%p" />
<Key
android:codes="66"
android:horizontalGap="2%p"
android:keyLabel="B"
android:keyWidth="8%p"
/>
<Key
android:codes="67"
android:horizontalGap="2%p"
android:keyLabel="C"
android:keyWidth="8%p"
/>
<Key
android:codes="68"
android:horizontalGap="2%p"
android:keyLabel="D"
android:keyWidth="8%p"
/>
<Key
android:codes="69"
android:horizontalGap="2%p"
android:keyLabel="E"
android:keyWidth="8%p"
/>
<Key
android:codes="70"
android:horizontalGap="2%p"
android:keyLabel="F"
android:keyWidth="8%p"
/>
<Key
android:codes="71"
android:horizontalGap="2%p"
android:keyLabel="G"
android:keyWidth="8%p"
/>
<Key
android:codes="72"
android:horizontalGap="2%p"
android:keyLabel="H"
android:keyWidth="8%p"
/>
<Key
android:codes="74"
android:horizontalGap="2%p"
android:keyLabel="J"
android:keyWidth="8%p"
/>
<Key
android:codes="75"
android:horizontalGap="2%p"
android:keyEdgeFlags="right"
android:keyLabel="K"
android:keyWidth="8%p" />
</Row>
<Row android:verticalGap="1%p">
<Key
android:codes="76"
android:horizontalGap="1%p"
android:keyEdgeFlags="left"
android:keyLabel="L"
android:keyWidth="8%p"
/>
<Key
android:codes="77"
android:horizontalGap="2%p"
android:keyLabel="M"
android:keyWidth="8%p"
/>
<Key
android:codes="78"
android:horizontalGap="2%p"
android:keyLabel="N"
android:keyWidth="8%p"
/>
<Key
android:codes="80"
android:horizontalGap="2%p"
android:keyLabel="P"
android:keyWidth="8%p" />
<Key
android:codes="81"
android:horizontalGap="2%p"
android:keyLabel="Q"
android:keyWidth="8%p"
/>
<Key
android:codes="82"
android:horizontalGap="2%p"
android:keyLabel="R"
android:keyWidth="8%p"
/>
<Key
android:codes="83"
android:horizontalGap="2%p"
android:keyLabel="S"
android:keyWidth="8%p"
/>
<Key
android:codes="84"
android:horizontalGap="2%p"
android:keyLabel="T"
android:keyWidth="8%p"
/>
<Key
android:codes="85"
android:horizontalGap="2%p"
android:keyLabel="U"
android:keyWidth="8%p" />
<Key
android:codes="86"
android:horizontalGap="2%p"
android:keyEdgeFlags="right"
android:keyLabel="V"
android:keyWidth="8%p" />
</Row>
<Row>
<Key
android:codes="87"
android:horizontalGap="7%p"
android:keyEdgeFlags="left"
android:keyLabel="W"
android:keyWidth="8%p" />
<Key
android:codes="88"
android:horizontalGap="2%p"
android:keyLabel="X"
android:keyWidth="8%p" />
<Key
android:codes="89"
android:horizontalGap="2%p"
android:keyLabel="Y"
android:keyWidth="8%p" />
<Key
android:codes="90"
android:horizontalGap="2%p"
android:keyLabel="Z"
android:keyWidth="8%p" />
<Key
android:codes="28207"
android:horizontalGap="2%p"
android:keyLabel="港"
android:keyWidth="8%p" />
<Key
android:codes="28595"
android:horizontalGap="2%p"
android:keyLabel="澳"
android:keyWidth="8%p" />
<Key
android:codes="23398"
android:horizontalGap="2%p"
android:keyLabel="学"
android:keyWidth="8%p" />
<Key
android:codes="39046"
android:horizontalGap="2%p"
android:keyEdgeFlags="right"
android:keyLabel="领"
android:keyWidth="8%p" />
<Key
android:codes="-3"
android:horizontalGap="2%p"
android:isRepeatable="false"
android:keyIcon="@mipmap/icon_delete"
android:keyWidth="13%p" />
</Row>
</Keyboard>
2.把xml文件创建好编辑好之后编写一个KeyboardUtil 类把需要展示键盘的Activity和edittext和该工具类绑定.
在构造方法中初始化控件和设置键盘所需要展示的样式.
public KeyboardUtil(Activity activity, EditText edit) {
mActivity = activity;
mEdit = edit;
provinceKeyboard = new Keyboard(activity, R.xml.province_abbreviation);
numberKeyboard = new Keyboard(activity, R.xml.number_or_letters);
mKeyboardView = (KeyboardView) activity.findViewById(R.id.keyboard_view);
mKeyboardView.setKeyboard(provinceKeyboard);
mKeyboardView.setEnabled(true);
mKeyboardView.setPreviewEnabled(false);
mKeyboardView.setOnKeyboardActionListener(listener);
}
mKeyboardView.setKeyboard(provinceKeyboard);这行代码就是让展示键盘的View展示省份的键盘.
mKeyboardView.setOnKeyboardActionListener(listener);然后设置监听器.
private KeyboardView.OnKeyboardActionListener listener = new KeyboardView.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) {
}
@Override
public void onKey(int primaryCode, int[] keyCodes) {
Editable editable = mEdit.getText();
int start = mEdit.getSelectionStart();
editable.insert(start, Character.toString((char) primaryCode));
}
};
设置键盘的监听器,每点击一个按钮都会调用一下onkey回调方法.
因为是调用自定义的软件盘所有需要把系统自带的软键盘给禁掉.
/**
* 禁掉系统软键盘
*/
public void hideSoftInputMethod() {
mActivity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
int currentVersion = android.os.Build.VERSION.SDK_INT;
String methodName = null;
if (currentVersion >= 16) {
// 4.2
methodName = "setShowSoftInputOnFocus";
} else if (currentVersion >= 14) {
// 4.0
methodName = "setSoftInputShownOnFocus";
}
if (methodName == null) {
mEdit.setInputType(InputType.TYPE_NULL);
} else {
Class<EditText> cls = EditText.class;
Method setShowSoftInputOnFocus;
try {
setShowSoftInputOnFocus = cls.getMethod(methodName, boolean.class);
setShowSoftInputOnFocus.setAccessible(true);
setShowSoftInputOnFocus.invoke(mEdit, false);
} catch (NoSuchMethodException e) {
mEdit.setInputType(InputType.TYPE_NULL);
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
KeyboardUtil中的代码如下
public class KeyboardUtil {
private Activity mActivity;
private KeyboardView mKeyboardView;
private EditText mEdit;
/**
* 省份简称键盘
*/
private Keyboard provinceKeyboard;
/**
* 数字与大写字母键盘
*/
private Keyboard numberKeyboard;
public KeyboardUtil(Activity activity, EditText edit) {
mActivity = activity;
mEdit = edit;
provinceKeyboard = new Keyboard(activity, R.xml.province_abbreviation);
numberKeyboard = new Keyboard(activity, R.xml.number_or_letters);
mKeyboardView = (KeyboardView) activity.findViewById(R.id.keyboard_view);
mKeyboardView.setKeyboard(provinceKeyboard);
mKeyboardView.setEnabled(true);
mKeyboardView.setPreviewEnabled(false);
mKeyboardView.setOnKeyboardActionListener(listener);
}
private KeyboardView.OnKeyboardActionListener listener = new KeyboardView.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) {
}
@Override
public void onKey(int primaryCode, int[] keyCodes) {
Editable editable = mEdit.getText();
int start = mEdit.getSelectionStart();
editable.insert(start, Character.toString((char) primaryCode));
}
};
/**
* 指定切换软键盘 isNumber false表示要切换为省份简称软键盘 true表示要切换为数字软键盘
*/
private void changeKeyboard(boolean isNumber) {
if (isNumber) {
mKeyboardView.setKeyboard(numberKeyboard);
} else {
mKeyboardView.setKeyboard(provinceKeyboard);
}
}
/**
* 软键盘展示状态
*/
public boolean isShow() {
return mKeyboardView.getVisibility() == View.VISIBLE;
}
/**
* 软键盘展示
*/
public void showKeyboard() {
int visibility = mKeyboardView.getVisibility();
if (visibility == View.GONE || visibility == View.INVISIBLE) {
mKeyboardView.setVisibility(View.VISIBLE);
}
}
/**
* 软键盘隐藏
*/
public void hideKeyboard() {
int visibility = mKeyboardView.getVisibility();
if (visibility == View.VISIBLE) {
mKeyboardView.setVisibility(View.INVISIBLE);
}
}
/**
* 禁掉系统软键盘
*/
public void hideSoftInputMethod() {
mActivity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
int currentVersion = android.os.Build.VERSION.SDK_INT;
String methodName = null;
if (currentVersion >= 16) {
// 4.2
methodName = "setShowSoftInputOnFocus";
} else if (currentVersion >= 14) {
// 4.0
methodName = "setSoftInputShownOnFocus";
}
if (methodName == null) {
mEdit.setInputType(InputType.TYPE_NULL);
} else {
Class<EditText> cls = EditText.class;
Method setShowSoftInputOnFocus;
try {
setShowSoftInputOnFocus = cls.getMethod(methodName, boolean.class);
setShowSoftInputOnFocus.setAccessible(true);
setShowSoftInputOnFocus.invoke(mEdit, false);
} catch (NoSuchMethodException e) {
mEdit.setInputType(InputType.TYPE_NULL);
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
3.在Activity中调用KeyboardUtil中的代码.
public class MainActivity extends AppCompatActivity {
private KeyboardUtil keyboardUtil;
private EditText mEditText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mEditText = findViewById(R.id.edit_text);
mEditText.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
if (keyboardUtil == null) {
keyboardUtil = new KeyboardUtil(MainActivity.this, mEditText);
keyboardUtil.hideSoftInputMethod();
keyboardUtil.showKeyboard();
} else {
keyboardUtil.showKeyboard();
}
return false;
}
});
}
}
Activity的布局文件核心代码:
<EditText
android:id="@+id/edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<android.inputmethodservice.KeyboardView
android:id="@+id/keyboard_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent" />
大功告成这就完成了第一种自定义键盘的功能.