简单自定义安全键盘(只能输入字母,数字,部分符号)

Posted 我的小侯子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单自定义安全键盘(只能输入字母,数字,部分符号)相关的知识,希望对你有一定的参考价值。

以前知道有个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="&#038;" />
        <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="\\&#092;" />
        <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="&#060;" />
        <!-->-->
        <Key
            android:codes="62"
            android:keyLabel="&#062;" />
        <Key
            android:codes="8364"
            android:keyLabel="€" />
        <Key
            android:codes="163"
            android:keyLabel="£" />
        <Key
            android:codes="165"
            android:keyLabel="¥" />
        <!--"-->
        <Key
            android:codes="34"
            android:keyLabel="&#034;" />
        <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);
    }

    /**
     * 关闭软键盘

以上是关于简单自定义安全键盘(只能输入字母,数字,部分符号)的主要内容,如果未能解决你的问题,请参考以下文章

C语言从键盘输入一个含有英文字母,英文符号,数字的字符串,如何过滤其中的字母??

Python中如何从键盘中输入字符串,统计字母,数字,符号和空格的个数?

JS正则表达式里 只能输入4-20位小写字母数字或汉字,,其他的符号空格啥都不能进 这个应该怎么写

angularjs 自定义指令控制input只能输入数字和字母

刚学C语言,不太懂。把键盘输入的由数字字符组成的字符串转换为相应的数字。例如把"123"转换为整数123

如何用switch语句判断从键盘输入字符的属性属于大写字母,小写字母,数字或其他的符号