Android自定义安全键盘
在银行APP里经常要自定义键盘,例如实现下面这样的效果

首先在xml文件里定义键盘
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:keyWidth="30%p"
android:horizontalGap="@dimen/keyboard_horizontalGap"
android:verticalGap="@dimen/keyboard_verticalGap"
android:keyHeight="47dp">
<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>
keyWidth:每一个按钮的宽度
keyHeight:每一个按钮高度,可以设置百分比
horizontalGap:水平间隔
verticalGap:竖直间隔
Row:一行
每一个按键都将会有一个 codes 值,代表键盘上的按键
KhKeyboardView
public class KhKeyboardView {
private Activity mContext;
private View parentView;
private KeyboardView mLetterView; //字母键盘view
private KeyboardView mNumberView; //数字键盘View
private Keyboard mNumberKeyboard; // 数字键盘
private Keyboard mLetterKeyboard; // 字母键盘
private Keyboard mSymbolKeyboard; // 符号键盘
private boolean isNumber = true; // 是否数字键盘
public static boolean isUpper = false; // 是否大写
private boolean isSymbol = false; // 是否是符号
private EditText mEditText;
private View headerView;
public void setEditText(EditText text) {
mEditText = text;
}
public KhKeyboardView(Activity context, View view) {
mContext = context;
parentView = view;
mNumberKeyboard = new Keyboard(mContext, R.xml.keyboard_numbers);
mLetterKeyboard = new Keyboard(mContext, R.xml.keyboard_word);
mSymbolKeyboard = new Keyboard(mContext, R.xml.keyboard_symbol);
mNumberView = (KeyboardView) parentView.findViewById(R.id.keyboard_view);
mLetterView = (KeyboardView) parentView.findViewById(R.id.keyboard_view_2);
mNumberView.setKeyboard(mNumberKeyboard);
mNumberView.setEnabled(true);
mNumberView.setPreviewEnabled(false);
mNumberView.setOnKeyboardActionListener(listener);
mLetterView.setKeyboard(mLetterKeyboard);
mLetterView.setEnabled(true);
mLetterView.setPreviewEnabled(true);
mLetterView.setOnKeyboardActionListener(listener);
headerView = parentView.findViewById(R.id.keyboard_header);
}
private KeyboardView.OnKeyboardActionListener listener = new KeyboardView.OnKeyboardActionListener() {
/**
* 按下,在onKey之前,可以在这里做一些操作,这里让有的没有按下的悬浮提示
* @param primaryCode
*/
@Override
public void onPress(int primaryCode) {
Log.d("primaryCode","onPress--"+primaryCode);
if (primaryCode == Keyboard.KEYCODE_SHIFT) {
mLetterView.setPreviewEnabled(false);
} else if (primaryCode == Keyboard.KEYCODE_DELETE) {
mLetterView.setPreviewEnabled(false);
} else if (primaryCode == 32) {
mLetterView.setPreviewEnabled(false);
} else {
mLetterView.setPreviewEnabled(true);
}
}
/**
* 松开
* @param primaryCode
*/
@Override
public void onRelease(int primaryCode) {
Log.d("primaryCode","onRelease--"+primaryCode);
}
/**
* 按下
* @param primaryCode
* @param keyCodes
*/
@Override
public void onKey(int primaryCode, int[] keyCodes) {
Log.d("primaryCode","onKey--"+primaryCode);
try {
if (mEditText == null)
return;
Editable editable = mEditText.getText();
int start = mEditText.getSelectionStart();
if (primaryCode == Keyboard.KEYCODE_CANCEL) {
// 隐藏键盘
hideKeyboard();
} else if (primaryCode == Keyboard.KEYCODE_DELETE || primaryCode == -35) {
// 回退键,删除字符
if (editable != null && editable.length() > 0) {
if (start > 0) {
editable.delete(start - 1, start);
}
}
} else if (primaryCode == Keyboard.KEYCODE_SHIFT) {
// 大小写切换
changeKeyboart();
mLetterView.setKeyboard(mLetterKeyboard);
} else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {
// 数字与字母键盘互换
if (isNumber) {
showLetterView();
showLetterView2();
} else {
showNumberView();
}
} else if (primaryCode == 90001) {
// 字母与符号切换
if (isSymbol) {
showLetterView2();
} else {
showSymbolView();
}
} else {
// 输入键盘值
editable.insert(start, Character.toString((char) primaryCode));
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onText(CharSequence text) {
}
@Override
public void swipeLeft() {
}
@Override
public void swipeRight() {
}
@Override
public void swipeDown() {
}
@Override
public void swipeUp() {
}
};
// 字母-符号,显示字母
private void showLetterView2() {
if (mLetterView != null) {
isSymbol = false;
mLetterView.setKeyboard(mLetterKeyboard);
}
}
// 字母-符号,显示符号
private void showSymbolView() {
try {
if (mLetterKeyboard != null) {
isSymbol = true;
mLetterView.setKeyboard(mSymbolKeyboard);
}
} catch (Exception e) {
}
}
// 数字-字母,显示字母键盘
private void showLetterView() {
try {
if (mLetterView != null && mNumberView != null) {
isNumber = false;
mLetterView.setVisibility(View.VISIBLE);
mNumberView.setVisibility(View.INVISIBLE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 数字-字母, 显示数字键盘
private void showNumberView() {
try {
if (mLetterView != null && mNumberView != null) {
isNumber = true;
mLetterView.setVisibility(View.INVISIBLE);
mNumberView.setVisibility(View.VISIBLE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 切换大小写
*/
private void changeKeyboart() {
List<Keyboard.Key> keyList = mLetterKeyboard.getKeys();
if (isUpper) {
// 大写切换小写
isUpper = false;
for (Keyboard.Key key : keyList) {
Drawable icon = key.icon;
if (key.label != null && isLetter(key.label.toString())) {
key.label = key.label.toString().toLowerCase();
key.codes[0] = key.codes[0] + 32;
}
}
} else {
// 小写切换成大写
isUpper = true;
for (Keyboard.Key key : keyList) {
if (key.label != null && isLetter(key.label.toString())) {
key.label = key.label.toString().toUpperCase();
key.codes[0] = key.codes[0] - 32;
}
}
}
}
/**
* 判断是否是字母
*/
private boolean isLetter(String str) {
String wordStr = "abcdefghijklmnopqrstuvwxyz";
return wordStr.contains(str.toLowerCase());
}
public void hideKeyboard() {
try {
int visibility = mLetterView.getVisibility();
if (visibility == View.VISIBLE) {
headerView.setVisibility(View.GONE);
mLetterView.setVisibility(View.GONE);
}
visibility = mNumberView.getVisibility();
if (visibility == View.VISIBLE) {
headerView.setVisibility(View.GONE);
mNumberView.setVisibility(View.GONE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 显示键盘
*
* @param editText
*/
public void showKeyboard(EditText editText) {
try {
this.mEditText = editText;
int visibility = 0;
int inputText = mEditText.getInputType();
headerView.setVisibility(View.VISIBLE);
switch (inputText) {
case InputType.TYPE_CLASS_NUMBER:
showNumberView();
break;
case InputType.TYPE_CLASS_PHONE:
showNumberView();
break;
case InputType.TYPE_NUMBER_FLAG_DECIMAL:
showNumberView();
break;
default:
showLetterView();
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
布局
<?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/rl_key"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#00000000"
android:orientation="vertical">
<View
android:id="@+id/keyboard_back_hide"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#7d7d7d"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/keyboard_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="visible">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="智能安全加密键盘"
android:textColor="#bfbfbf"
android:textSize="15sp" />
<TextView
android:id="@+id/keyboard_finish"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:padding="14dp"
android:text="完成"
android:textColor="#ffffff"
android:textSize="15sp" />
</RelativeLayout>
<ImageView
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginBottom="10dp"
android:background="#555457" />
<FrameLayout
android:id="@+id/keyboard_layer"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.kh.keyboard.CustomKeyboardView
android:id="@+id/keyboard_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#7d7d7d"
android:focusable="true"
android:focusableInTouchMode="true"
android:keyBackground="@drawable/keyboard_number_selector_bg"
android:keyPreviewLayout="@null"
android:keyTextColor="#ffffff"
android:visibility="gone" />
<com.kh.keyboard.CustomKeyboardView
android:id="@+id/keyboard_view_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#7d7d7d"
android:focusable="true"
android:focusableInTouchMode="true"
android:keyBackground="@drawable/keyboard_selector_bg"
android:keyPreviewHeight="90dp"
android:keyPreviewLayout="@layout/keyboard_key_preview_layout"
android:keyPreviewOffset="45dp"
android:keyTextColor="#ffffff"
android:visibility="gone" />
</FrameLayout>
</LinearLayout>
</RelativeLayout>
public class CustomKeyboardView extends KeyboardView {
private Context context;
public CustomKeyboardView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
try {
List<Keyboard.Key> keys = getKeyboard().getKeys();
for (Keyboard.Key key : keys) {
// Log.e("KEY", "Drawing key with code " + key.codes[0]);
if (key.codes[0] == -5) {
Drawable dr = (Drawable) context.getResources().getDrawable(R.drawable.keyboard_word_del_layerlist);
dr.setBounds(key.x, key.y, key.x + key.width, key.y + key.height);
dr.draw(canvas);
} else if (key.codes[0] == -35) {
Drawable dr = (Drawable) context.getResources().getDrawable(R.drawable.keyboard_word_del_layerlist2);
dr.setBounds(key.x, key.y, key.x + key.width, key.y + key.height);
dr.draw(canvas);
} else if (key.codes[0] == -1) {
Drawable dr = (Drawable) context.getResources().getDrawable(R.drawable.keyboard_word_shift_layerlist);
Drawable dr_da = (Drawable) context.getResources().getDrawable(R.drawable.keyboard_word_shift_layerlist_da);
dr.setBounds(key.x, key.y, key.x + key.width, key.y + key.height);
dr_da.setBounds(key.x, key.y, key.x + key.width, key.y + key.height);
if (KhKeyboardView.isUpper) {
dr_da.draw(canvas);
} else {
dr.draw(canvas);
}
} else if (key.codes[0] == -2 || key.codes[0] == 90001) {
Drawable dr = (Drawable) context.getResources().getDrawable(R.drawable.keyboard_selector_blue_bg);
dr.setBounds(key.x, key.y, key.x + key.width, key.y + key.height);
dr.draw(canvas);
drawText(canvas, key);
} else {
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void drawText(Canvas canvas, Keyboard.Key key) {
try {
Rect bounds = new Rect();
Paint paint = new Paint();
paint.setTextAlign(Paint.Align.CENTER);
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
if (key.label != null) {
String label = key.label.toString();
Field field;
if (label.length() > 1 && key.codes.length < 2) {
int labelTextSize = 0;
try {
field = KeyboardView.class.getDeclaredField("mLabelTextSize");
field.setAccessible(true);
labelTextSize = (int) field.get(this);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
paint.setTextSize(labelTextSize);
paint.setTypeface(Typeface.DEFAULT_BOLD);
} else {
int keyTextSize = 0;
try {
field = KeyboardView.class.getDeclaredField("mLabelTextSize");
field.setAccessible(true);
keyTextSize = (int) field.get(this);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
paint.setTextSize(keyTextSize);
paint.setTypeface(Typeface.DEFAULT);
}
paint.getTextBounds(key.label.toString(), 0, key.label.toString()
.length(), bounds);
canvas.drawText(key.label.toString(), key.x + (key.width / 2),
(key.y + key.height / 2) + bounds.height() / 2, paint);
} else if (key.icon != null) {
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);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class KeyBoardDialogUtils implements View.OnClickListener {
protected View view;
protected Dialog popWindow;
protected Activity mContext;
private EditText contentView;
private List<String> contentList;
private KhKeyboardView keyboardUtil;
public KeyBoardDialogUtils(Activity mContext) {
try {
this.mContext = mContext;
if (contentList == null) {
contentList = new ArrayList<>();
}
if (popWindow == null) {
view = LayoutInflater.from(mContext).inflate(R.layout.keyboard_key_board_popu, null);
view.findViewById(R.id.keyboard_finish).setOnClickListener(this);
view.findViewById(R.id.keyboard_back_hide).setOnClickListener(this);
}
popWindow.setContentView(view);
popWindow.setCanceledOnTouchOutside(true);
Window mWindow = popWindow.getWindow();
mWindow.setWindowAnimations(R.style.keyboard_popupAnimation);
mWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
mWindow.setGravity(Gravity.BOTTOM | Gravity.FILL_HORIZONTAL);
mWindow.setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
popWindow.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
if (contentView != null && contentView.isFocused()) {
contentView.clearFocus();
}
}
});
initView();
} catch (Exception e) {
e.printStackTrace();
}
}
private void initView() {
try {
if (keyboardUtil == null)
keyboardUtil = new KhKeyboardView(mContext, view);
} catch (Exception e) {
e.printStackTrace();
}
}
public void show(final EditText editText) {
editText.setFocusable(true);
editText.setFocusableInTouchMode(true);
editText.requestFocus();
popWindow.show();
keyboardUtil.showKeyboard(editText);
}
public void dismiss() {
if (popWindow != null && popWindow.isShowing()) {
popWindow.dismiss();
}
}
@Override
public void onClick(View v) {
try {
int i = v.getId();
if (i == R.id.keyboard_finish) {
keyboardUtil.hideKeyboard();
dismiss();
} else if (i == R.id.keyboard_back_hide) {
keyboardUtil.hideKeyboard();
dismiss();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用
et = (EditText) findViewById(R.id.et);
keyBoardDialogUtils = new KeyBoardDialogUtils(this);
et.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
keyBoardDialogUtils.show(et);
}
});
Android自定义安全键盘的更多相关文章
- Android开发案例 - 自定义虚拟键盘
所有包含IM功能的App(如微信, 微博, QQ, 支付宝等)都提供了Emoji表情之类的虚拟键盘, 如下图: 本文只着重介绍如何实现输入法键盘和自定义虚拟键盘的流畅切换, 而不介绍如何实现虚 ...
- 关于在android手机中腾讯、阿里产品不自定义虚拟键盘的想法
1,自定义虚拟键盘,影响用户体验.你每个用户的喜好不一样,都有自己心仪的一款输入法.腾讯或是阿里设计出来的输入法很难满足上亿用户的喜好,到时候又是一场口水战,再说了就是专业的输入法肯定要比应用里嵌套的 ...
- (转)[原] Android 自定义View 密码框 例子
遵从准则 暴露您view中所有影响可见外观的属性或者行为. 通过XML添加和设置样式 通过元素的属性来控制其外观和行为,支持和重要事件交流的事件监听器 详细步骤见:Android 自定义View步骤 ...
- Android 自定义View合集
自定义控件学习 https://github.com/GcsSloop/AndroidNote/tree/master/CustomView 小良自定义控件合集 https://github.com/ ...
- [原] Android 自定义View 密码框 例子
遵从准则 暴露您view中所有影响可见外观的属性或者行为. 通过XML添加和设置样式 通过元素的属性来控制其外观和行为,支持和重要事件交流的事件监听器 详细步骤见:Android 自定义View步骤 ...
- android自定义view系列:认识activity结构
标签: android 自定义view activity 开发中虽然我们调用Activity的setContentView(R.layout.activity_main)方法显示View视图,但是vi ...
- android 自定义view 前的基础知识
本篇文章是自己自学自定义view前的准备,具体参考资料来自 Android LayoutInflater原理分析,带你一步步深入了解View(一) Android视图绘制流程完全解析,带你一步步深入了 ...
- 【朝花夕拾】Android自定义View篇之(八)多点触控(上)MotionEvent简介
前言 在前面的文章中,介绍了不少触摸相关的知识,但都是基于单点触控的,即一次只用一根手指.但是在实际使用App中,常常是多根手指同时操作,这就需要用到多点触控相关的知识了.多点触控是在Android2 ...
- 【朝花夕拾】Android自定义View篇之(六)Android事件分发机制(中)从源码分析事件分发逻辑及经常遇到的一些“诡异”现象
前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/11039252.html]谢谢! 在上一篇文章[[朝花夕拾]Android自定义View篇之(五 ...
随机推荐
- 让你成功安装vscode中go的相关插件
注意:该演示环境是windows环境,linux和mac环境操作思路一样 vscode中有很多go的相关插件,非常好用如下:gocodegopkgsgo-outlinego-symbolsgurugo ...
- 51、css初识
前端内容就分三部分html.css.javascript(js),对一个网页来说html相当于是一个裸体的人,css相当于给这个人穿上了衣服,javascript相当于给这个人赋予动作行为,今天我们要 ...
- 【java】文件操作java.io.File
package 文件操作; import java.io.File; import java.io.IOException; public class TestFile { public static ...
- Linux中dos2unix批量转换
有时候遇到多层目录下的文件格式需要转换,dos2unix 没有-r之类的递归指令,所以需要与find还有管道结合. find -type f | xargs dos2unix -o
- bzoj 4569: [Scoi2016]萌萌哒
Description 一个长度为n的大数,用S1S2S3...Sn表示,其中Si表示数的第i位,S1是数的最高位,告诉你一些限制条件,每个条 件表示为四个数,l1,r1,l2,r2,即两个长度相同的 ...
- 搭建eclipse+tomcat开发环境
JDK 1.6 Eclipse IDE For JEE Version Tomcat 6.0 tomcatPluginV33 //eclipse平台上的插件,但它并不是tomcat本身,需要安装独立 ...
- zepto的返回顶部scrollTop的动画解决方法
写移动端的时候,引入的zepto.js里的animate不包括scrollTop,所以返回顶部的时候,没有动画的效果.这里我使用的是setInterval的方法.代码详情如下 <!DOCTYPE ...
- java实现发送邮件服务器,SMTP协议发送邮件
1.采用SMTP的邮件发送协议.准备:在网易注册一个邮箱,进入设置开启SMTP/pop3协议 2.接下来就是java代码实现了,下面都有注释,就不多做解释了. public class mail { ...
- UWP 在Xaml中使用cu和fcu资源
之前一直不知道这个,最近看微软的WTS项目更新,在Xaml中定义了 xmlns:fcu ="http://schemas.microsoft.com/winfx/2006/xaml/pres ...
- g4e基础篇#2 Git分布式版本控制系统的优势
g4e 是 Git for Enterprise Developer的简写,这个系列文章会统一使用g4e作为标识,便于大家查看和搜索. 章节目录 前言 1. 基础篇: 为什么要使用版本控制系统 Git ...