Let's make a simple keyboard together

In today's China, mobile financial services have become a trend, and institutions such as Alipay, WeChat, and banks have all launched their own financial and wealth management apps. Money is a good thing, so there will always be someone on your mind. The money on the mobile phone is invisible and intangible, but the large numbers still tempt some good people to want to do something. The first thing that can be thought of is to make a fuss about the input method, record the account password entered by the user and upload it secretly. . Faced with this situation, each app has the same strategy, that is, develop a keyboard by itself, let users use this secure keyboard to input passwords, and make the input method of good people invalid.

China Merchants Bank’s is relatively simple, just a numeric keyboard, while Agricultural Bank’s is a little more complicated, and also provides an alphabetic keyboard. Then let's imitate the Agricultural Bank of China today and try to use a numeric and alphabetic keyboard.

The relevant code is on github , welcome to star and fork


China Merchants Bank security keyboard

Preliminary knowledge

Customizing the keyboard is actually pretty easy, at least a lot easier than I thought. We only need to use two classes provided by the system: Keyboard and KeyboardView. From the class name, we can guess that as long as the written keyboard layout file is sent to the keyboard class, the corresponding custom function can be realized. Is it that simple? Not at all! let's get started

keyboard drawing

Let's take a look at a simple button layout file.

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:horizontalGap="0px"
    android:verticalGap="0px"
    android:keyHeight="7.5%p"
    android:keyWidth="30%p">
    <Row android:verticalGap="1%p">
        <Key
            android:codes="49"
            android:keyLabel="1"
            android:horizontalGap="2%p">

        </Key>
        <Key
            android:codes="50"
            android:keyLabel="2"
            android:horizontalGap="2%p">

        </Key>
        <Key
            android:codes="51"
            android:keyLabel="3"
            android:horizontalGap="2%p">

        </Key>
    </Row>
    <Row>
        <Key
            android:codes="-2"
            android:keyLabel="abc"
            android:horizontalGap="2%p">

        </Key>
        <Key
            android:codes="48"
            android:keyLabel="0"
            android:horizontalGap="2%p">

        </Key>
        <Key
            android:codes="-5"
            android:isRepeatable="true"
            android:keyIcon="@mipmap/ic_delete"
            android:horizontalGap="2%p">

        </Key>
    </Row>
</Keyboard>
Simple button layout

Just look at the button layout, nothing else, let's analyze how this button layout is built.
The width and height of the keyboard do not need to bother us. We manage the width and height of each key. The attributes corresponding to this width and height are android:keyWidth, android:keyHeight, the gap between rows (the gap below) can be used android:vertical, and the * between columns (left gap) Yes Gapandroid:horizontalGap.
The line wrapping of the keys is Rowused for processing, and each key Keyis in it, which android:keyLabelis the text on the key and the text android:codesoutput on the EditText. Note that this codes value cannot be filled with a string casually. It is generally a unicode value. For example, 48 above corresponds to 0 in decimal. You can compare these with the ASCIItable. If you want to output a real string, you need to use attributes keyOutputText. If you want to place an image without text on the button, you can use android:keyIconattributes. In order to realize the continuous deletion of long press of the delete key, you can use the android:isRepeatableattribute
. The unit of width, height and spacing can be either pixels, inches, etc., or a percentage relative to the base value, ending with the %pend. I suggest that it is better to use the percentage unit in the development process. After all, the screen adaptation is still the most reliable percentage layout. We will talk about the calculation method later. I will
not introduce some other attributes. You can look at some information in the reference article at the end of the article.

Here, the keys of the entire numeric keyboard are posted to illustrate the calculation steps of the percentage. By the way, the layout of the keys is placed in the res/xml folder.

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:horizontalGap="0px"
    android:verticalGap="0px"
    android:keyHeight="7.5%p"
    android:keyWidth="30%p">
    <Row android:verticalGap="1%p">
        <Key
            android:codes="49"
            android:keyLabel="1"
            android:horizontalGap="2%p">

        </Key>
        <Key
            android:codes="50"
            android:keyLabel="2"
            android:horizontalGap="2%p">

        </Key>
        <Key
            android:codes="51"
            android:keyLabel="3"
            android:horizontalGap="2%p">

        </Key>
    </Row>
    <Row android:verticalGap="1%p">
        <Key
            android:codes="52"
            android:keyLabel="4"
            android:horizontalGap="2%p">

        </Key>
        <Key
            android:codes="53"
            android:keyLabel="5"
            android:horizontalGap="2%p">

        </Key>
        <Key
            android:codes="54"
            android:keyLabel="6"
            android:horizontalGap="2%p">

        </Key>
    </Row>
    <Row android:verticalGap="1%p">
        <Key
            android:codes="55"
            android:keyLabel="7"
            android:horizontalGap="2%p">

        </Key>
        <Key
            android:codes="56"
            android:keyLabel="8"
            android:horizontalGap="2%p">

        </Key>
        <Key
            android:codes="57"
            android:keyLabel="9"
            android:horizontalGap="2%p">

        </Key>
    </Row>
    <Row>
        <Key
            android:codes="-2"
            android:keyLabel="abc"
            android:horizontalGap="2%p">

        </Key>
        <Key
            android:codes="48"
            android:keyLabel="0"
            android:horizontalGap="2%p">

        </Key>
        <Key
            android:codes="-5"
            android:isRepeatable="true"
            android:keyIcon="@mipmap/ic_delete"
            android:horizontalGap="2%p">

        </Key>
    </Row>
</Keyboard>

I globally defined the height of the button to be 7.5%p7.5% of the height of the screen, and the width is 30% of the width of the screen. In this way, every horizontal gap between my buttons (100-30*3)/4=2.5is 2% if I write it casually. Haha, it's that simple.

After the key drawing is over, put it on the keyboard, let's take a look at the layout file of the keyboard

<?xml version="1.0" encoding="utf-8"?>
<android.inputmethodservice.KeyboardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="wrap_content"
    android:id="@+id/view_keyboard"
    android:background="#999999"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:keyBackground="@drawable/selector_keyboard_key"
    android:keyPreviewHeight="64dip"
    android:keyPreviewLayout="@layout/view_keyboard_preview"
    android:keyTextColor="@android:color/black"
    android:keyTextSize="24sp"
    android:labelTextSize="18sp"
    android:paddingTop="8dip"
    android:paddingBottom="8dip"
    android:shadowColor="#FFFFFF"
    android:shadowRadius="0.0"
    android:visibility="gone">

</android.inputmethodservice.KeyboardView>

Briefly explain the properties that have not been seen before
android:keyBackground: keyboard background image
android:keyPreviewLayout: the layout of the preview image when the keyboard is clicked, here is a TextView. The preview image is the prompt layout file that pops up briefly after clicking the button

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content" android:layout_height="wrap_content"
    android:background="@android:color/holo_red_light"
    android:textColor="@android:color/white"
    android:gravity="center"
    android:textSize="24sp">

</TextView>

android:keyPreviewHeight: The height of the preview image when the keyboard is clicked
android:keyTextColor: The color of the
android:keyTextSizekey text: The size of the key text
android:labelTextSize: If the keys of text + image are set at the same time, use this property to set. I'm more puzzled here. Obviously text and charts cannot be displayed on the button at the same time. The meaning of this attribute should not be understood in this way
android:shadowColor android:shadowRadius: don't ask me, anyway, without these two attributes, the text on the button will be blurred.

Finally, let's take a look at the keyboard placement. At the bottom of the relative layout, it is hidden by default.

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.renyu.keyboarddemo.MainActivity">
    <LinearLayout
        android:id="@+id/layout_root"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <View
            android:layout_width="match_parent"
            android:layout_height="400dip"></View>
        <com.renyu.keyboarddemo.KeyBoardEditText
            android:id="@+id/ed_main"
            android:layout_width="match_parent"
            android:layout_height="50dip"
            android:background="@android:color/holo_orange_dark"/>
    </LinearLayout>
    <LinearLayout
        android:id="@+id/layout_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_alignParentBottom="true"
        android:background="#999999"
        android:visibility="gone">
        <include layout="@layout/content_keyboard"></include>
    </LinearLayout>
</RelativeLayout>

keyboard function

We put the keyboard key output processing function on an EditText. The general process is to initialize a Keyboardclass, then assign the class to keyboardViewit, and set KeyboardView.OnKeyboardActionListenerit to process the corresponding key callback event.

Initialize the keyboard, get the alphabet keyboard and numeric keyboard here

private fun initEditView() {
    keyboradNumber = Keyboard(context_, R.xml.keyboard_number)
    keyboradLetter = Keyboard(context_, R.xml.keyboard_letter)
}

Then you can pass

keyboardView.isPreviewEnabled = true

Switch for keyboard preview function

After completing the above steps, you can add the button callback event

    public interface OnKeyboardActionListener {
        // 当用户按下一个键时调用。在调用onKey之前调用。如果之前定义的codes有问题,primaryCode为0
        void onPress(int primaryCode);
        // 当用户释放键时调用
        void onRelease(int primaryCode);
        // 之前codes字段定义的值
        void onKey(int primaryCode, int[] keyCodes);
        // 如果之前在keyOutputText定义过数值,则按键之后会在此回调中进行响应
        void onText(CharSequence text);
        // 下面都是在键盘上进行手势操作
        void swipeLeft();
        void swipeRight();
        void swipeDown();
        void swipeUp();
    }

Let's focus on the onKey method.
I don’t know if you have noticed before that I have several negative values ​​in the button layout. In fact, these negative values ​​are meaningful. I have used several parameters defined by the system here.

    public static final int KEYCODE_SHIFT = -1;
    public static final int KEYCODE_MODE_CHANGE = -2;
    public static final int KEYCODE_CANCEL = -3;
    public static final int KEYCODE_DONE = -4;
    public static final int KEYCODE_DELETE = -5;
    public static final int KEYCODE_ALT = -6;

You can understand the meaning by looking at the name. Here I use -2 to switch the keyboard type, -1 to switch the case, -5 to delete, and -4 to complete. Basically, your custom code values ​​are best to use negative numbers, why? Because the system is all positive.

I just copied the 2 callback methods I used, and judged the code value on the button by judging the primaryCode value. If it is not a function key, convert the unicode value into a character and enter it into the text box

keyboardView.setOnKeyboardActionListener(object : KeyboardView.OnKeyboardActionListener {
    override fun onPress(primaryCode: Int) {
        canShowPreview(primaryCode)
    }

    override fun onKey(primaryCode: Int, keyCodes: IntArray?) {
        val editable = text
        val start = selectionStart
        // 删除功能
        if (primaryCode == Keyboard.KEYCODE_DELETE) {
            if (editable.isNotEmpty() && start>0) {
                editable.delete(start-1, start)
            }
        }
        // 字母键盘与数字键盘切换
        else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {
            changeKeyBoard(!changeLetter)
        }
        // 完成
        else if (primaryCode == Keyboard.KEYCODE_DONE) {
            keyboardView.visibility = View.GONE
            viewGroup.visibility = View.GONE
            listener?.hide()
        }
        // 切换大小写
        else if (primaryCode == Keyboard.KEYCODE_SHIFT) {
            changeCapital(!isCapital)
            keyboardView.keyboard = keyboradLetter
        }
        else {
            editable.insert(start, Character.toString(primaryCode.toChar()))
        }
    }
})

Let's take a look at the code when the numeric keyboard and the alphabetic keyboard are switched. Different keyboards are reset to the keyboard view, just keyboardView?.keyboardcall

fun changeKeyBoard(letter: Boolean) {
    changeLetter = letter
    if (changeLetter) {
        keyboardView?.keyboard = keyboradLetter
    }
    else {
        keyboardView?.keyboard = keyboradNumber
    }
}

Generally, the keyboard is displayed by touching the text box, and the keyboard is collapsed by clicking the return key. Note that the system input method needs to be hidden, otherwise it will be messy

override fun onTouchEvent(event: MotionEvent?): Boolean {
    KeyboardUtils.hideSoftInput(this)
    if (event?.action == MotionEvent.ACTION_UP) {
        if (keyboardView?.visibility != View.VISIBLE) {
            keyboardView?.visibility = View.VISIBLE
            viewGroup?.visibility = View.VISIBLE
        }
    }
    return true
}

override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
    if (keyCode == KeyEvent.KEYCODE_BACK && keyboardView?.visibility != View.GONE
            && viewGroup?.visibility != View.GONE) {
        keyboardView?.visibility = View.GONE
        viewGroup?.visibility = View.GONE
        return true
    }
    return super.onKeyDown(keyCode, event)
}

override fun onAttachedToWindow() {
    super.onAttachedToWindow()
    KeyboardUtils.hideSoftInput(this)
}

override fun onDetachedFromWindow() {
    super.onDetachedFromWindow()
    KeyboardUtils.hideSoftInput(this)
}

If you have a strong need for UI customization of keyboard keys, you can traverse and customize by overriding the KeyboardView onDraw()method.keyboard.getKeys()

season finale

There is no big ending, just use it

Reference article

Simple implementation of
Android custom keyboard Android custom numeric keyboard implementation method

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325556847&siteId=291194637