Android自定义数字键盘(支持随机数字)

前言

也是最近想写个demo玩玩,不知道写哪个方面的好,就随便写了一个自定义的键盘,比较简单,但是做了封装,支持jitpack库依赖(这也是我第一次开源自己的库,比较水的一个开源项目,仅供学习使用)。

概述

主要完成了以下功能:
1.自定义数字键盘
2.切换到随机数字键盘
3.自定义确定和删除等键(向外抛出接口,感觉设计的挺好)

下面先看下运行效果吧

效果图片

使用方法

1.在项目build.gradle文件中添加jitpack,添加jitpcak就够了。

allprojects {
    repositories {
        jcenter()
        maven { url 'https://jitpack.io' }
    }
}

2.在module 的build.gradle文件添加依赖

  compile 'com.github.Simon986793021:NumberKeyboard:v1.0'

3.在布局文件中添加布局

<com.wind.keyboard.OfoKeyboardView
        android:id="@+id/keyboard_view"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:focusable="true"
        android:paddingTop="0dp"
        android:focusableInTouchMode="true"
        android:keyBackground="@drawable/bg_keyboardview"
        android:keyPreviewOffset="0dp"
        android:keyTextColor="#000"
        android:shadowColor="#fff"
        android:shadowRadius="0.0"
        android:layout_alignParentBottom="true"
        />

4.在MainActivity调用。

 editText= (EditText) findViewById(R.id.et_numberplate);
        changebutton= (Button) findViewById(R.id.bt_change_keyboard);
        final OfoKeyboard keyboard = new OfoKeyboard(MainActivity.this);//获取到keyboard对象
        changebutton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                keyboard.attachTo(editText,true);//eiditext绑定keyboard,true表示随机数字
            }
        });
        editText.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                keyboard.attachTo(editText,false);//eiditext绑定keyboard,false表示普通数字键盘

            }
        });
        /*
        确定按钮
         */
        keyboard.setOnOkClick(new OfoKeyboard.OnOkClick() {
            @Override
            public void onOkClick() {
                Log.i(">>>>>>","点击了确定");
                Toast.makeText(MainActivity.this,editText.getText().toString(),Toast.LENGTH_SHORT).show();
            }
        });
        //隐藏键盘按钮
        keyboard.setOnCancelClick(new OfoKeyboard.OnCancelClcik() {
            @Override
            public void onCancelClick() {
                Toast.makeText(MainActivity.this,"隐藏键盘",Toast.LENGTH_SHORT).show();
            }
        });

只需要这些简单的代码就能够实现一个自己定义的键盘了。

实现过程

1.新建一个keyboard布局

在看这个代码之前需要了解keyboard的属性:
不清楚属性,怎么画页面,不懂的请移步这篇博客

Android键盘属性

在 res 新建一个xml文件,然后在xml新建一个keyboard.xml

里面代码如下

<?xml version="1.0" encoding="utf-8"?>
<Keyboard
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyHeight="9%p"
    android:keyWidth="25%p"
    android:horizontalGap="0dp">
    <Row>
        <Key
            android:codes="49"
            android:keyLabel="1"/>
        <Key
            android:codes="50"
            android:keyLabel="2"/>
        <Key
            android:codes="51"
            android:keyLabel="3"/>
        <Key
            android:codes="-5"
            android:keyHeight="18%p"
            android:keyEdgeFlags="right"
            android:isRepeatable="true"
            android:keyIcon="@drawable/icon_delete_32dp"/>
    </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"/>
        <Key
            android:codes="-4"
            android:keyLabel="确定"
            android:keyEdgeFlags="right"
            android:keyHeight="18%p"/>
    </Row>
    <Row>
        <Key
            android:codes="46"
            android:keyLabel="."/>
        <Key
            android:codes="48"
            android:keyLabel="0"/>
        <Key
            android:codes="-3"
            android:keyIcon="@drawable/icon_hide_keyboard"/>
    </Row>
</Keyboard>

这个布局就是自己自定义键盘的布局实现,有了布局,显然是不够的。

2.自定义KeyboardView

package com.wind.keyboard;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.util.AttributeSet;
import android.util.Log;

import java.lang.reflect.Field;
import java.util.List;

/**
 * Created by zhangcong on 2017/8/24.
 */

public class OfoKeyboardView extends KeyboardView {
    private Context context;
    private Keyboard keyboard;
    public OfoKeyboardView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context=context;
        Log.i(">>>>>","构造函数被调用了");
    }
    /**
     * 重新画一些按键
     */
    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        keyboard = this.getKeyboard();
        List<Keyboard.Key> keys = null;
        if (keyboard != null) {
            keys = keyboard.getKeys();
        }

        if (keys != null) {
            for (Keyboard.Key key : keys) {
                // 数字键盘的处理
                if (key.codes[0] == -4) {
                    drawKeyBackground(R.drawable.bg_keyboardview_yes, canvas, key);
                    drawText(canvas, key);
                }
            }
        }
    }

    private void drawKeyBackground(int drawableId, Canvas canvas, Keyboard.Key key) {
        Drawable npd = context.getResources().getDrawable(
                drawableId);
        int[] drawableState = key.getCurrentDrawableState();
        if (key.codes[0] != 0) {
            npd.setState(drawableState);
        }
        npd.setBounds(key.x, key.y, key.x + key.width, key.y
                + key.height);
        npd.draw(canvas);
    }

    private void drawText(Canvas canvas, Keyboard.Key key) {
        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);
        }

    }
}

3.KeyBoard的对象的创建:

package com.wind.keyboard;

import android.app.Activity;
import android.content.Context;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.os.Build;
import android.text.Editable;
import android.text.InputType;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

/**
 * Created by zhangcong on 2017/8/28.
 */

public class    OfoKeyboard {
    private Activity activity;
    private Keyboard keyboard;
    private OfoKeyboardView keyboardView;
    private EditText editText;
    private boolean isRandom=false;
    public  OfoKeyboard (Activity activity )
    {
        this.activity=activity;
        keyboardView= (OfoKeyboardView) activity.findViewById(R.id.keyboard_view);
    }
    //点击事件触发
    public void attachTo(EditText editText,boolean isRandom){

        /*
        切换键盘需要重新new Keyboard对象,否则键盘不会改变,keyboardView放到构造函数里面,避免每次点击重新new 对象,提高性能
         */
        keyboard=new Keyboard(activity,R.xml.keyboard);
        this.isRandom=isRandom;
        Log.i(">>>>>","attachTo");
        this.editText=editText;
        hideSystemSofeKeyboard(activity,editText);
        showSoftKeyboard();
    }


    private void showSoftKeyboard() {
        if (keyboard == null) {
            keyboard = new Keyboard(activity, R.xml.keyboard);
        }
        if(keyboardView==null)
        {
            keyboardView= (OfoKeyboardView) activity.findViewById(R.id.keyboard_view);
        }
        if (isRandom)
        {
            randomKeyboardNumber();
        }
        else {
            keyboardView.setKeyboard(keyboard);
        }
            keyboardView.setEnabled(true);
            keyboardView.setPreviewEnabled(false);
            keyboardView.setVisibility(View.VISIBLE);
            keyboardView.setOnKeyboardActionListener(listener);
    }

    private KeyboardView.OnKeyboardActionListener listener=new KeyboardView.OnKeyboardActionListener() {
        @Override
        public void onPress(int primaryCode) {

        }

        @Override
        public void onRelease(int primaryCode) {

        }

        @Override
        public void onKey(int primaryCode, int[] keyCodes) {
            Editable editable=editText.getText();
            int start =editText.getSelectionStart();
            if (primaryCode==Keyboard.KEYCODE_DELETE)//key  codes 为-5
            {
                if (editable!=null&&editable.length()>0)
                {
                    if (start>0)
                    {
                        editable.delete(start-1,start);
                    }
                }
            }
            else if (primaryCode==Keyboard.KEYCODE_CANCEL)
            {
                hideKeyBoard();
                if (mCancelClick!=null)
                {
                    mCancelClick.onCancelClick();
                }
            }
            else if (primaryCode==Keyboard.KEYCODE_DONE)
            {
                hideKeyBoard();
                if (mOkClick!=null)
                {
                    mOkClick.onOkClick();
                }
            }
           else {
                Log.i(">>>>>>",primaryCode+"1");
                Log.i(">>>>>>",(char) primaryCode+"2");
                editable.insert(start,Character.toString((char) primaryCode));
            }
        }

        @Override
        public void onText(CharSequence text) {

        }

        @Override
        public void swipeLeft() {

        }

        @Override
        public void swipeRight() {

        }

        @Override
        public void swipeDown() {

        }

        @Override
        public void swipeUp() {

        }
    };
    public interface OnOkClick {
        void onOkClick();
    }
    public interface OnCancelClcik{
        void onCancelClick();
    }
    public OnOkClick mOkClick;
    public OnCancelClcik mCancelClick;
    public void setOnOkClick(OnOkClick onOkClick)
    {
        this.mOkClick=onOkClick;
    }
    public void setOnCancelClick (OnCancelClcik onCancelClick)
    {
        this.mCancelClick=onCancelClick;
    }
    private void hideKeyBoard() {
        int visibility=keyboardView.getVisibility();
        if (visibility==KeyboardView.VISIBLE)
        {
            keyboardView.setVisibility(KeyboardView.GONE);
        }
    }
    private boolean isNumber(String str) {
        String wordstr = "0123456789";
        return wordstr.contains(str);
    }

    private void randomKeyboardNumber() {
        List<Keyboard.Key> keyList = keyboard.getKeys();
        // 查找出0-9的数字键
        List<Keyboard.Key> newkeyList = new ArrayList<Keyboard.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();
        }
     //   hideKeyBoard();
        keyboardView.setKeyboard(keyboard);
    }

    /**
     * 隐藏系统键盘
     *
     * @param editText
     */
    public static void hideSystemSofeKeyboard(Context context, EditText editText) {
        Log.i(">>>>>","hide");
        int sdkInt = Build.VERSION.SDK_INT;
        if (sdkInt >= 11) {
            try {
                Class<EditText> cls = EditText.class;
                Method setShowSoftInputOnFocus;
                setShowSoftInputOnFocus = cls.getMethod("setShowSoftInputOnFocus", boolean.class);
                setShowSoftInputOnFocus.setAccessible(true);
                setShowSoftInputOnFocus.invoke(editText, false);

            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            editText.setInputType(InputType.TYPE_NULL);
        }
        // 如果软键盘已经显示,则隐藏
        InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
    }
}

到这里,自定义键盘就全部完成了。

总结

自定义键盘就是通过自定义一个键盘布局,然后通过keyboardView来展示出来。个人感觉没什么需要掌握的,不过可以学习一下代码的封装技巧。

Github地址

自定义键盘是比较简单的,但是个人感觉可以看看里面的一些代码封装的技巧,如果你觉得对你有帮助,麻烦来个star吧。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容