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篇之(五 ...
随机推荐
- Hadoop:Rack Awareness
副本的放置对HDFS可靠性和性能至关重要. 优化副本放置HDFS有别于其他大多数分布式文件系统. 这是一个功能,需要大量的调优和经验. 基于机架感知(rack awareness)的副本放置策略的目的 ...
- 多线程day01
多线程作为Java中很重要的一个知识点,在此还是有必要总结一下的. 一.线程的生命周期及五种基本状态 关于Java中线程的生命周期,首先看一下下面这张较为经典的图: 上图中基本上囊括了Java中多线程 ...
- JMeter循环控制器循环次数使用变量控制注意事项
1.进入循环控制器之前变量要有值: 2.BeanShell处理文件,读取行数,赋值给变量,要有相应的Sampler,不然脚本不会运行. 对于单个线程来说,假如设置了循环2次,线程启动后,运行结束,此时 ...
- Linux简介,虚拟机安装,网络设置,桌面和vim安装
Linux简介: linux代表系统内核.Linux系统指基于Linux内核的操作系统,由内核和程序结合组成.比较流行的发行版本由RedHat Linux.Fedora.Centos.Debian.U ...
- Linux 文件API
9/19/2017 开始攻读<LinuxC编程实战>,这是相关的笔记 1.创建 int creat(const char *filename, mode_t mode); 参数mode指 ...
- node作为客户端请求第三方
var http = require('http'); let util = require('util'); http.get('http://www.imooc.com/u/card',funct ...
- iOS开发之Xcode常用调试技巧总结
转载自:iOS开发之Xcode常用调试技巧总结 最近在面试,面试过程中问到了一些Xcode常用的调试技巧问题.平常开发过程中用的还挺顺手的,但你要突然让我说,确实一脸懵逼.Debug的技巧很多,比如最 ...
- 常规流(Normal flow)
连我自己把float和绝对定位,都称为脱离文档流,想想概念又不那么清晰,于是寻找了W3C资料来理解,才发觉不应该叫文档流. 资料 英文:https://www.w3.org/TR/CSS22/visu ...
- Java I/O---File类
1.File概述 File(文件)类可能有一定的误导性,它不仅仅指代的是文件.它既能代表一个特定的文件的名称,又能代表一个目录下的一组文件集的名称,这样就可以用集合List方法调用和遍历.实际上Fil ...
- SQL Server 2016 行级别权限控制
背景 假如我们有关键数据存储在一个表里面,比如人员表中包含员工.部门和薪水信息.只允许用户访问各自部门的信息,但是不能访问其他部门.一般我们都是在程序端实现这个功能,而在sqlserver2016以后 ...