android自定义软键盘

本篇文章将会介绍3种android自定义软键盘的应用场景以及代码编写,分别是:普通的自定义软键盘;每次弹出都会改变数字顺序的自定义密码键盘;能与webview交互的自定义密码键盘。以上说的这三种其实本质上没有太大区别,只是细节调用和写法上有略微区别,我们项目里用到是最后一种,但是网上对最后一种的介绍很少,这三种自定义软键盘的介绍顺序也是我的推导顺序,第一种是基础,有了基础后续推导会容易很多,如果你暂时用不到后面的可以只看第一种,有些印象就好。

一、普通基础自定义键盘

1.动态效果图:

2.设计思路:

  • 首先在res下创建xml目录,在xml中定义数字键盘和英文键盘;
  • 自定义EditText继承EditText并且实现KeyboardView.OnKeyboardActionListener接口用来监听软键盘的点击事件,从而控制软键盘的切换、预览以及输入框的内容变化;
  • 判断软键盘弹出是否会遮挡输入框,如果会则使得页面上移到不会遮挡为止,软键盘隐藏时注意页面下移相同距离。

3.软键盘的相关属性介绍:

  • key的相关属性:

  • row的相关属性:

  • KeyboardView的相关属性:
  • ASCII码对应表:

4.字母键盘的xml文件编写:

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

        </Key>
        <Key
            android:codes="119"
            android:keyLabel="w"
            android:horizontalGap="1.81%p">

        </Key>
        <Key
            android:codes="101"
            android:keyLabel="e"
            android:horizontalGap="1.81%p">

        </Key>
        <Key
            android:codes="114"
            android:keyLabel="r"
            android:horizontalGap="1.81%p">

        </Key>
        <Key
            android:codes="116"
            android:keyLabel="t"
            android:horizontalGap="1.81%p">

        </Key>
        <Key
            android:codes="121"
            android:keyLabel="y"
            android:horizontalGap="1.81%p">

        </Key>
        <Key
            android:codes="117"
            android:keyLabel="y"
            android:horizontalGap="1.81%p">

        </Key>
        <Key
            android:codes="105"
            android:keyLabel="i"
            android:horizontalGap="1.81%p">

        </Key>
        <Key
            android:codes="111"
            android:keyLabel="o"
            android:horizontalGap="1.81%p">

        </Key>
        <Key
            android:codes="112"
            android:keyLabel="p"
            android:horizontalGap="1.81%p">

        </Key>
    </Row>
    <Row android:verticalGap="1%p">
        <Key
            android:codes="97"
            android:keyLabel="a"
            android:keyWidth="9%p"
            android:horizontalGap="5.5%p">

        </Key>
        <Key
            android:codes="115"
            android:keyLabel="s"
            android:keyWidth="9%p"
            android:horizontalGap="1%p">

        </Key>
        <Key
            android:codes="100"
            android:keyLabel="d"
            android:keyWidth="9%p"
            android:horizontalGap="1%p">

        </Key>
        <Key
            android:codes="102"
            android:keyLabel="f"
            android:keyWidth="9%p"
            android:horizontalGap="1%p">

        </Key>
        <Key
            android:codes="103"
            android:keyLabel="g"
            android:keyWidth="9%p"
            android:horizontalGap="1%p">

        </Key>
        <Key
            android:codes="104"
            android:keyLabel="h"
            android:keyWidth="9%p"
            android:horizontalGap="1%p">

        </Key>
        <Key
            android:codes="106"
            android:keyLabel="j"
            android:keyWidth="9%p"
            android:horizontalGap="1%p">

        </Key>
        <Key
            android:codes="107"
            android:keyLabel="k"
            android:keyWidth="9%p"
            android:horizontalGap="1%p">

        </Key>
        <Key
            android:codes="108"
            android:keyLabel="l"
            android:keyWidth="9%p"
            android:horizontalGap="1%p">

        </Key>
    </Row>
    <Row android:verticalGap="1%p">
        <Key
            android:codes="-1"
            android:keyLabel="大写"
            android:keyWidth="17%p"
            android:horizontalGap="1%p">

        </Key>
        <Key
            android:codes="122"
            android:keyLabel="z"
            android:horizontalGap="1%p">

        </Key>
        <Key
            android:codes="120"
            android:keyLabel="x"
            android:horizontalGap="1%p">

        </Key>
        <Key
            android:codes="99"
            android:keyLabel="c"
            android:horizontalGap="1%p">

        </Key>
        <Key
            android:codes="118"
            android:keyLabel="v"
            android:horizontalGap="1%p">

        </Key>
        <Key
            android:codes="98"
            android:keyLabel="b"
            android:horizontalGap="1%p">

        </Key>
        <Key
            android:codes="110"
            android:keyLabel="n"
            android:horizontalGap="1%p">

        </Key>
        <Key
            android:codes="109"
            android:keyLabel="m"
            android:horizontalGap="1%p">

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

        </Key>
    </Row>
    <Row>
        <Key
            android:codes="-2"
            android:keyLabel="123"
            android:keyWidth="20%p"
            android:horizontalGap="1%p">

        </Key>
        <Key
            android:codes="32"
            android:keyLabel="space"
            android:keyWidth="48%p"
            android:horizontalGap="5%p">

        </Key>
        <Key
            android:codes="-4"
            android:keyLabel="完成"
            android:keyWidth="20%p"
            android:horizontalGap="5%p">

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

5.字母键盘的xml文件编写:

<?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>

6.自定义软键盘相关代码及注释:

package com.example.mycustomkeyboard;

import android.content.Context;
import android.hardware.input.InputManager;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.support.v7.widget.AppCompatEditText;
import android.text.Editable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created by zd on 2018/4/2.
 */

public class KeyBoardEditText extends AppCompatEditText implements KeyboardView.OnKeyboardActionListener {

    /**数字键盘*/
    private Keyboard keyboardNumber;
    /**字母键盘*/
    private Keyboard keyboardLetter;
    private ViewGroup viewGroup;
    private KeyboardView keyboardView;

    /**是否发生键盘切换*/
    private boolean changeLetter = false;
    /**是否为大写*/
    private boolean isCapital = false;
    private int[] arrays = new int[]{Keyboard.KEYCODE_SHIFT, Keyboard.KEYCODE_MODE_CHANGE,
            Keyboard.KEYCODE_CANCEL, Keyboard.KEYCODE_DONE, Keyboard.KEYCODE_DELETE,
            Keyboard.KEYCODE_ALT, 32};
    private List<Integer> noLists = new ArrayList<>();
    private OnKeyboardStateChangeListener listener;

    public KeyBoardEditText(Context context) {
        super(context);
        initEditView();
    }

    public KeyBoardEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        initEditView();
    }

    public KeyBoardEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initEditView();
    }

    /**初始化数字和字母键盘*/
    private void initEditView() {
        keyboardNumber = new Keyboard(getContext(), R.xml.keyboard_num);
        keyboardLetter = new Keyboard(getContext(), R.xml.keyboard_letter);

        for (int i=0; i<arrays.length; i++) {
            noLists.add(arrays[i]);
        }
    }

    /**
     * 设置软键盘刚弹出的时候显示字母键盘还是数字键盘
     * @param vg 包裹KeyboardView的ViewGroup
     * @param kv KeyboardView
     * @param keyboard_num 是否显示数字键盘
     */
    public void setKeyboardType (ViewGroup vg, KeyboardView kv, boolean keyboard_num) {

        viewGroup = vg;
        keyboardView = kv;
        if (keyboard_num) {
            keyboardView.setKeyboard(keyboardNumber);
            changeLetter = false;
        } else {
            keyboardView.setKeyboard(keyboardLetter);
            changeLetter = true;
        }

        //显示预览
        keyboardView.setPreviewEnabled(true);
        //为KeyboardView设置按键监听
        keyboardView.setOnKeyboardActionListener(this);
    }

    public void setOnKeyBoardStateChangeListener(OnKeyboardStateChangeListener listener) {
        this.listener = listener;
    }

    @Override
    public void onPress(int primaryCode) {

        canShowPreview(primaryCode);
    }

    /**
     * 判断是否需要预览Key
     *
     * @param primaryCode keyCode
     */
    private void canShowPreview(int primaryCode) {

        if (noLists.contains(primaryCode)) {
            keyboardView.setPreviewEnabled(false);
        } else {
            keyboardView.setPreviewEnabled(true);
        }
    }

    @Override
    public void onRelease(int primaryCode) {

    }

    @Override
    public void onKey(int primaryCode, int[] keyCodes) {

        Editable editable = getText();
        int start = getSelectionStart();
        switch (primaryCode) {

            case Keyboard.KEYCODE_DELETE://删除
                if (editable != null && editable.length() > 0 && start > 0) {
                    editable.delete(start-1, start);
                }
                break;
            case Keyboard.KEYCODE_MODE_CHANGE://字母键盘与数字键盘切换
                changeKeyBoard(!changeLetter);
                break;
            case Keyboard.KEYCODE_DONE://完成
                keyboardView.setVisibility(View.GONE);
                viewGroup.setVisibility(GONE);
                if (listener != null) {
                    listener.hide();
                }
                break;
            case Keyboard.KEYCODE_SHIFT://大小写切换
                changeCapital(!isCapital);
                keyboardView.setKeyboard(keyboardLetter);
                break;
            default:
                editable.insert(start, Character.toString((char)primaryCode));
                break;
        }
    }

    /**切换键盘大小写*/
    private void changeCapital(boolean b) {

        isCapital = b;
        List<Keyboard.Key> lists = keyboardLetter.getKeys();
        for (Keyboard.Key key: lists) {
            if (key.label != null && isKey(key.label.toString())) {
                if (isCapital) {
                    key.label = key.label.toString().toUpperCase();
                    key.codes[0] = key.codes[0] - 32;
                } else  {
                    key.label = key.label.toString().toLowerCase();
                    key.codes[0] = key.codes[0] + 32;
                }
            } else if (key.label != null && key.label.toString().equals("小写")) {
                key.label = "大写";
            } else if (key.label != null && key.label.toString().equals("大写")) {
                key.label = "小写";
            }
        }
    }

    /** * 判断此key是否正确,且存在 * * @param key * @return */
    private boolean isKey(String key) {
        String lowercase = "abcdefghijklmnopqrstuvwxyz";
        if (lowercase.indexOf(key.toLowerCase()) > -1) {
            return true;
        }
        return false;
    }


    /**切换键盘类型*/
    private void changeKeyBoard(boolean b) {
        changeLetter = b;
        if (changeLetter) {
            keyboardView.setKeyboard(keyboardLetter);
        } else {
            keyboardView.setKeyboard(keyboardNumber);
        }
    }

    @Override
    public void onText(CharSequence text) {

    }

    @Override
    public void swipeLeft() {

    }

    @Override
    public void swipeRight() {

    }

    @Override
    public void swipeDown() {

    }

    @Override
    public void swipeUp() {

    }

    public interface OnKeyboardStateChangeListener {
        void show();
        void hide();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        hideSystemSoftInput();
        if (event.getAction() == MotionEvent.ACTION_UP) {
            if (keyboardView.getVisibility() != VISIBLE) {
                keyboardView.setVisibility(VISIBLE);
                viewGroup.setVisibility(VISIBLE);
                if (listener != null)
                listener.show();
            }
        }
        return true;
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        if (keyCode == KeyEvent.KEYCODE_BACK && (viewGroup.getVisibility() != GONE
        || keyboardView.getVisibility() != GONE)) {
            viewGroup.setVisibility(GONE);
            keyboardView.setVisibility(GONE);
            if (listener != null)
            listener.hide();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        hideSystemSoftInput();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        hideSystemSoftInput();
    }

    /**隐藏系统软键盘*/
    private void hideSystemSoftInput() {
        InputMethodManager manager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        manager.hideSoftInputFromWindow(getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
    }
}

7.使用时的页面布局以及调用方法:

  • view_keyboard_preview.xml
  • <?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>
  • content_keyboard.xml
  • <?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>
  • activity_main.xml
  • <?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">
        <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.example.mycustomkeyboard.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>
    
  • 调用方法和键盘遮挡输入框时的移动内容代码:
  • public class MainActivity extends AppCompatActivity {
    
        private KeyBoardEditText text;
        private KeyboardView keyboardView;
        private LinearLayout layout;
        private LinearLayout root;
        private int height = 0;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            text = (KeyBoardEditText) findViewById(R.id.ed_main);
            keyboardView = (KeyboardView) findViewById(R.id.view_keyboard);
            layout = (LinearLayout) findViewById(R.id.layout_main);
            root = (LinearLayout) findViewById(R.id.layout_root);
            text.setKeyboardType(layout, keyboardView, true);
            text.setOnKeyBoardStateChangeListener(new KeyBoardEditText.OnKeyboardStateChangeListener() {
                @Override
                public void show() {
                    root.post(new Runnable() {
                        @Override
                        public void run() {
    
                            int[] pos = new int[2];
                            //获取编辑框在整个屏幕中的坐标
                            text.getLocationOnScreen(pos);
                            //编辑框的Bottom坐标和键盘Top坐标的差
                            height = (pos[1] + text.getHeight()) -
                                    (getScreenHeight(MainActivity.this) - keyboardView.getHeight());
                            if (height > 0) {
                                root.scrollBy(0, height + dp2px(MainActivity.this, 16));
                            }
                        }
                    });
                }
    
                @Override
                public void hide() {
    
                    if (height > 0) {
                        root.scrollBy(0, -(height + dp2px(MainActivity.this, 16)));
                    }
                }
            });
    
            //Log.i("zhangdi", getLngAndLat(this));
        }
    
        /**
         * 获得屏幕高度
         *
         * @param context
         * @return
         */
        public static int getScreenHeight(Context context) {
            WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            DisplayMetrics displayMetrics = new DisplayMetrics();
            wm.getDefaultDisplay().getMetrics(displayMetrics);
            return displayMetrics.heightPixels;
        }
    
        /**
         * dp转px
         *
         * @param context
         * @param dpVal
         * @return dip
         */
        public static int dp2px(Context context, float dpVal) {
            return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources().getDisplayMetrics());
        }

二、每次弹出都会改变数字顺序的自定义密码键盘

1.动态效果图:

2.设计思路:

  • 在res下创建xml目录,在xml中定义数字键盘;
  • 自定义键盘继承KeyboardView并且实现KeyboardView.OnKeyboardActionListener接口,每次显示键盘的时候使键盘上的数字随机排列显示,用接口回调控制输入框显示;
  • 每次显示的时候判断软键盘是否会遮挡输入框,如果遮挡则使输入框所在部分内容上移,软键盘隐藏的时候把内容移回原位;

3,遇到的问题:

  • 软键盘左右不能都有空隙,如果软键盘左侧有空隙,软键盘宽度不能占满整个屏幕。解决办法:让软键盘左侧有空隙,在软键盘的布局文件外面嵌套一层viewgroup布局,为这个布局设置与软键盘布局相同的底色;
  • 如果在xml里设置‘自定义软键盘’和‘完成’,没办法使得‘自定义软键盘’这几个字居中,也控制不好‘完成’的位置。解决方法:把这两项不写在自定义数字键盘的xml文件里,而是写在页面布局嵌套软键盘布局的viewgroup中。

4.数字键盘的xml文件:

<?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.5%p">

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

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

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

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

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

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

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

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

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

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

        </Key>

        <Key
            android:codes="-3"
            android:keyLabel="隐藏"
            android:horizontalGap="2.5%p">

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

5.自定义数字键盘代码和注释:

package com.example.mycustomkeyboard;

import android.content.Context;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.text.Editable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

/**
 * Created by zd on 2018/4/24.
 * 自定义键盘在布局文件中须确保在整体布局的底部,不要和输入框在相同的根布局内
 */

public class MyKeyBoardView extends KeyboardView implements KeyboardView.OnKeyboardActionListener {

    //数字键盘
    private Keyboard keyboard;
    //对应的输入框
    private EditText editText;
    //为防止自定义键盘覆盖输入框,根布局向上的移动高度
    private int height = 0;
    //输入框所在的根布局
    private ViewGroup root;
    //自定义软键盘所在的根布局
    private ViewGroup keyBoardRoot;
    //完成按钮
    private TextView complete;

    public MyKeyBoardView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyKeyBoardView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * 关联自定义键盘与输入框,以及输入框所在的根布局
     * 需要注意此方法需要在输入框的OnTouchListener中当MotionEvent为MotionEvent.ACTION_UP时调用,
     * 否则无法正确阻止系统软键盘的弹出
     * @param et 输入框
     * @param root 输入框所在的根布局
     */
    public void setAttachToEditText(EditText et, ViewGroup root, ViewGroup keyBoardRoot) {

        if (keyboard == null) {
            keyboard = new Keyboard(getContext(), R.xml.keyboard_random_num);
        }
        this.editText = et;
        this.root = root;
        this.keyBoardRoot = keyBoardRoot;
        complete = keyBoardRoot.findViewById(R.id.complete);
        complete.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                hideKeyBoard();
            }
        });
        editText.requestFocus();
        hideSystemSoftInput();
        showMyKeyBoard();
    }

    /**显示自定随机数键盘*/
    private void showMyKeyBoard() {

        randomKeyboardNumber();
        setKeyboard(keyboard);
        setEnabled(true);
        setPreviewEnabled(false);
        showResize();
        keyBoardRoot.setVisibility(VISIBLE);
        setVisibility(VISIBLE);
        setOnKeyboardActionListener(this);
    }

    /**根据输入框的底部坐标与自定义键盘的顶部坐标之间的差值height,
     * 判断自定义键盘是否覆盖住了输入框,如果覆盖则使输入框所在的根布局移动height*/
    private void showResize() {

        root.post(new Runnable() {
            @Override
            public void run() {

                int[] pos = new int[2];
                //获取编辑框在整个屏幕中的坐标
                editText.getLocationOnScreen(pos);
                //编辑框的Bottom坐标和键盘Top坐标的差
                height = (pos[1] + editText.getHeight()) -
                        (getScreenHeight(getContext()) - keyBoardRoot.getHeight());
                if (height > 0) {
                    root.scrollBy(0, height + dp2px(getContext(), 16));
                }
            }
        });
    }

    /**自定义键盘隐藏时,判断输入框所在的根布局是否向上移动了height,如果移动了则需再移回来*/
    private void hideResize() {
        if (height > 0) {
            root.scrollBy(0, -(height + dp2px(getContext(), 16)));
        }
    }

    /**获取手机屏幕高度*/
    public static int getScreenHeight(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(displayMetrics);
        return displayMetrics.heightPixels;
    }

    /**将px转换成dp*/
    public static int dp2px(Context context, float dpVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources().getDisplayMetrics());
    }

    /**打乱数字键盘顺序*/
    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))) {
                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();
        }
    }

    private class KeyModel {

        private int code;
        private String lable;

        public KeyModel(int code, String lable) {
            this.code = code;
            this.lable = lable;
        }

        public int getCode() {
            return code;
        }

        public void setCode(int code) {
            this.code = code;
        }

        public String getLable() {
            return lable;
        }

        public void setLable(String lable) {
            this.lable = lable;
        }
    }

    /**判断key是数字键还是完成键*/
    private boolean isNumber(Keyboard.Key key) {

        if (key.codes[0] < 0) {
            return false;
        }

        return true;
    }

    /**隐藏系统键盘*/
    private void hideSystemSoftInput() {

        InputMethodManager manager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        manager.hideSoftInputFromWindow(editText.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
    }

    @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();

        switch (primaryCode) {

            case Keyboard.KEYCODE_DELETE://删除
                if (editable != null && editable.length() > 0 && start > 0) {
                    editable.delete(start-1, start);
                }
                break;
            case Keyboard.KEYCODE_DONE://完成
                break;
            case Keyboard.KEYCODE_CANCEL://取消、隐藏
                hideKeyBoard();
                break;
            default://插入数字
                editable.insert(start, Character.toString((char)primaryCode));
        }
    }

    /**隐藏键盘*/
    private void hideKeyBoard() {

        if (getVisibility() == VISIBLE) {
            keyBoardRoot.setVisibility(GONE);
            setVisibility(GONE);
            hideResize();
        }
    }

    @Override
    public void onText(CharSequence text) {

    }

    @Override
    public void swipeLeft() {

    }

    @Override
    public void swipeRight() {

    }

    @Override
    public void swipeDown() {

    }

    @Override
    public void swipeUp() {

    }
}

6.使用时的布局文件和调用方法:

my_keyboard_view.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mykeyboard_root"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#999999"
    android:layout_alignParentBottom="true"
    android:visibility="gone">

    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="自定义软键盘"
        android:gravity="center"
        android:textSize="18sp"
        android:textColor="@android:color/white"
        android:paddingTop="10dp"/>

    <TextView
        android:id="@+id/complete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="完成"
        android:textSize="18sp"
        android:layout_alignParentRight="true"
        android:layout_marginRight="10dp"
        android:layout_marginTop="10dp"
        android:textColor="@color/colorPrimary"/>

    <com.example.mycustomkeyboard.MyKeyBoardView
        android:id="@+id/mykeyboard"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#999999"
        android:layout_marginTop="10dp"
        android:keyBackground="@drawable/key_drawable"
        android:keyTextColor="@android:color/black"
        android:layout_below="@id/title"
        android:visibility="gone"/>

</RelativeLayout>

activity_main2.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.mycustomkeyboard.Main2Activity">

    <LinearLayout
        android:id="@+id/root"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <EditText
            android:id="@+id/et1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="30dp"/>

        <EditText
            android:id="@+id/et2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="30dp"/>

        <EditText
            android:id="@+id/et3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="30dp"/>

        <EditText
            android:id="@+id/et4"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="30dp"/>

        <EditText
            android:id="@+id/et"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="30dp"/>


    </LinearLayout>

    <include layout="@layout/my_keyborad_view"/>
</RelativeLayout>

使用方法:

package com.example.mycustomkeyboard;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

public class Main2Activity extends AppCompatActivity implements View.OnTouchListener {

    private EditText et;
    private EditText et1;
    private EditText et2;
    private EditText et3;
    private EditText et4;
    private MyKeyBoardView keyBoardView;
    private LinearLayout root;
    private RelativeLayout keyboardRoot;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

        et = (EditText) findViewById(R.id.et);
        et1 = (EditText) findViewById(R.id.et1);
        et2 = (EditText) findViewById(R.id.et2);
        et3 = (EditText) findViewById(R.id.et3);
        et4 = (EditText) findViewById(R.id.et4);
        root = (LinearLayout) findViewById(R.id.root);
        keyBoardView = (MyKeyBoardView) findViewById(R.id.mykeyboard);
        keyboardRoot = (RelativeLayout) findViewById(R.id.mykeyboard_root);
        et.setOnTouchListener(this);
        et1.setOnTouchListener(this);
        et2.setOnTouchListener(this);
        et3.setOnTouchListener(this);
        et4.setOnTouchListener(this);

    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            keyBoardView.setAttachToEditText((EditText) v, root, keyboardRoot);
        }
        return true;
    }
}

三、能与webview交互的自定义密码键盘

1.动态效果图:


2.设计思路:

  • 与第二种的密码键盘设计思路基本一致,数字键盘的xml文件直接用第二种的就可以,不过软键盘按键控制输入框显示的时候需要调用html中的方法进行显示;
  • 判断软件盘是否遮挡输入框时也需要html传递输入框所在位置参数载进行计算,需要注意的是html中传递的输入框位置是相对于页面左上角的,所以需要减去webview的滑动距离,才能计算出输入框相对于屏幕左上角的位置,才能计算出软键盘是否会遮挡输入框。

3.自定义数字键盘代码以及注释:

package com.example.mycustomkeyboard;

import android.app.Activity;
import android.content.Context;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.text.Editable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.webkit.WebView;
import android.widget.EditText;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

/**
 * Created by zd on 2018/4/24.
 * 自定义键盘在布局文件中须确保在整体布局的底部,不要和输入框在相同的根布局内
 */

public class MyKeyBoardViewWeb extends KeyboardView implements KeyboardView.OnKeyboardActionListener {

    //数字键盘
    private Keyboard keyboard;
    //为防止自定义键盘覆盖输入框,根布局向上的移动高度
    private int height = 0;
    //输入框所在的根布局
    private ViewGroup root;
    //自定义软键盘所在的根布局
    private ViewGroup keyBoardRoot;
    //完成按钮
    private TextView complete;
    private WebView web;

    public MyKeyBoardViewWeb(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyKeyBoardViewWeb(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * 关联自定义键盘与输入框,以及输入框所在的根布局
     * @param root 输入框所在的根布局
     */
    public void setAttach(WebView web, int height, ViewGroup root, ViewGroup keyBoardRoot) {

        if (keyboard == null) {
            keyboard = new Keyboard(getContext(), R.xml.keyboard_random_num);
        }
        this.web = web;
        this.keyBoardRoot = keyBoardRoot;
        this.root = root;
        complete = keyBoardRoot.findViewById(R.id.complete);
        complete.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                hideKeyBoard();
            }
        });
        hideSystemSoftInput();
        showMyKeyBoard(height);
    }

    /**显示自定随机数键盘*/
    private void showMyKeyBoard(int height) {

        randomKeyboardNumber();
        setKeyboard(keyboard);
        setEnabled(true);
        setPreviewEnabled(false);
        showResize(height);
        keyBoardRoot.setVisibility(VISIBLE);
        setVisibility(VISIBLE);
        setOnKeyboardActionListener(this);
    }

    /**根据输入框的底部坐标与自定义键盘的顶部坐标之间的差值height,
     * 判断自定义键盘是否覆盖住了输入框,如果覆盖则使输入框所在的根布局移动height*/
    private void showResize(final int h) {

        root.post(new Runnable() {
            @Override
            public void run() {

                //获取屏幕高度
                int screenHeight = getScreenHeight(getContext());
                //获取软键盘高度
                int keyHeight = keyBoardRoot.getMeasuredHeight();
                //获取编辑框底部距离页面顶部的高度
                int etHeight = dp2px(getContext(), h);
                //获取webview的内容滚动距离
                int scrollY = web.getScrollY();
                //编辑框底部高度去除webview内容滚动距离获取编辑框底部与屏幕顶部之间的高度
                // ,与软键盘与屏幕顶部之间的高度差,如果差值大于0则证明软键盘覆盖住编辑框了,需要内容上移。
                height = etHeight - scrollY - (screenHeight - keyHeight);
                if (height > 0) {
                    root.scrollBy(0, height + dp2px(getContext(), 32));
                }
            }
        });
    }

    /**自定义键盘隐藏时,判断输入框所在的根布局是否向上移动了height,如果移动了则需再移回来*/
    private void hideResize() {
        if (height > 0) {
            root.scrollBy(0, -(height + dp2px(getContext(), 32)));
        }
    }

    /**获取手机屏幕高度*/
    public static int getScreenHeight(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(displayMetrics);
        return displayMetrics.heightPixels;
    }

    /**将px转换成dp*/
    public static int dp2px(Context context, float dpVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources().getDisplayMetrics());
    }

    public static int px2dp(Context context, float dpVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, dpVal, context.getResources().getDisplayMetrics());
    }

    /**打乱数字键盘顺序*/
    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))) {
                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();
        }
    }

    private class KeyModel {

        private int code;
        private String lable;

        public KeyModel(int code, String lable) {
            this.code = code;
            this.lable = lable;
        }

        public int getCode() {
            return code;
        }

        public void setCode(int code) {
            this.code = code;
        }

        public String getLable() {
            return lable;
        }

        public void setLable(String lable) {
            this.lable = lable;
        }
    }

    /**判断key是数字键还是完成键*/
    private boolean isNumber(Keyboard.Key key) {

        if (key.codes[0] < 0) {
            return false;
        }

        return true;
    }

    /**隐藏系统键盘*/
    public void hideSystemSoftInput() {

        InputMethodManager manager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        manager.hideSoftInputFromWindow(((Activity)getContext()).getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
    }

    @Override
    public void onPress(int primaryCode) {

    }

    @Override
    public void onRelease(int primaryCode) {

    }

    @Override
    public void onKey(int primaryCode, int[] keyCodes) {

        switch (primaryCode) {

            case Keyboard.KEYCODE_DELETE://删除
                web.loadUrl("javascript:del()");
                break;
            case Keyboard.KEYCODE_DONE://完成
                break;
            case Keyboard.KEYCODE_CANCEL://取消、隐藏
                hideKeyBoard();
                break;
            default://插入数字
                String content = Character.toString((char)primaryCode);
                web.loadUrl("javascript:insert("+content+")");
        }
    }

    /**隐藏键盘*/
    private void hideKeyBoard() {

        if (getVisibility() == VISIBLE) {
            keyBoardRoot.setVisibility(GONE);
            setVisibility(GONE);
            hideResize();
        }
    }

    @Override
    public void onText(CharSequence text) {

    }

    @Override
    public void swipeLeft() {

    }

    @Override
    public void swipeRight() {

    }

    @Override
    public void swipeDown() {

    }

    @Override
    public void swipeUp() {

    }
}

4.使用的html相关代码:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0 , maximum-scale=1.0, user-scalable=0">
  
    <title>Show.html</title>
   
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
<script type="text/javascript">
var name;
function init(s) {
  name = s;
  setLoseFocus();
  sub();
}

function setFocus() {//设置焦点
  var et = document.getElementById(name);
  et.focus();
}

function setLoseFocus() {//取消焦点
  var et = document.getElementById(name);
  et.blur();
}

function sub(){
  var et = document.getElementById(name);
  var height = getPos(et);
  console.info(height);
  window.demo.showInput(height);//调用android方法,弹出软键盘
  <!--console.info("哈哈");-->
}

function getPos(o) //取元素坐标
{
    var y = o.offsetTop;
    y += o.offsetHeight;
    return y;
}

function del() {//删除
  var str = document.getElementById(name).value;
  var strNew = str.substring(0,str.length-1);
  document.getElementById(name).value = strNew;
}

function insert(str) {//插入
  var s = document.getElementById(name).value;
  var strNew = s + str;
  document.getElementById(name).value = strNew;
}
</script>
  </head>
  
  <body>
  <br/>
  <br/>
  <br/>
  <input type="text" id="txt1" οnclick="init('txt1')" value="">
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <input type="text" id="txt2" οnclick="init('txt2')" value="">
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <br/>
  <input type="text" id="txt" οnclick="init('txt')" value="">
  </body>
</html>

5.使用时的布局以及调用方法:

my_keyboard_view_web.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mykeyboard_root"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#999999"
    android:layout_alignParentBottom="true"
    android:visibility="gone">

    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="自定义软键盘"
        android:gravity="center"
        android:textSize="18sp"
        android:textColor="@android:color/white"
        android:paddingTop="10dp"/>

    <TextView
        android:id="@+id/complete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="完成"
        android:textSize="18sp"
        android:layout_alignParentRight="true"
        android:layout_marginRight="10dp"
        android:layout_marginTop="10dp"
        android:textColor="@color/colorPrimary"/>

    <com.example.mycustomkeyboard.MyKeyBoardViewWeb
        android:id="@+id/mykeyboard"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#999999"
        android:layout_marginTop="10dp"
        android:keyBackground="@drawable/key_drawable"
        android:keyTextColor="@android:color/black"
        android:layout_below="@id/title"
        android:visibility="gone"/>

</RelativeLayout>

activity_webview.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.mycustomkeyboard.WebviewActivity">

    <RelativeLayout
        android:id="@+id/root"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <WebView
            android:id="@+id/web"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </RelativeLayout>

    <include layout="@layout/my_keyborad_view_web"/>

</RelativeLayout>

调用方法:

package com.example.mycustomkeyboard;

import android.app.Activity;
import android.os.Bundle;
import android.text.Editable;
import android.view.View;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

public class WebviewActivity extends Activity {

    private WebView web;
    private MyKeyBoardViewWeb keyBoardView;
    private RelativeLayout root;
    private RelativeLayout keyboardRoot;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_webview);

        root = (RelativeLayout) findViewById(R.id.root);
        keyBoardView = (MyKeyBoardViewWeb) findViewById(R.id.mykeyboard);
        keyboardRoot = (RelativeLayout) findViewById(R.id.mykeyboard_root);

        web = findViewById(R.id.web);
        web.getSettings().setJavaScriptEnabled(true);
        web.getSettings().setDomStorageEnabled(true);
        web.addJavascriptInterface(new DemoJavaScriptInterface(),"demo");
        web.loadUrl("file:///android_asset/index.html");
    }

    public class DemoJavaScriptInterface {

        @JavascriptInterface
        public void showInput(final int height) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (keyBoardView.getVisibility() != View.VISIBLE) {
                        keyBoardView.setAttach(web, height, root, keyboardRoot);
                    }
                }
            });
        }
    }
}
最后附上demo下载地址,使用android studio添加moudle可以直接运行看看效果: 下载demo

  • 9
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android 中,自定义软键盘需要实现一个继承自 InputMethodService 的服务,这个服务会在用户打开软键盘时被调用。下面是一些步骤来创建自定义软键盘: 1. 创建一个新的 Android 项目,并在 AndroidManifest.xml 文件中声明一个新的服务: ```xml <service android:name=".CustomKeyboard" android:label="Custom Keyboard" android:permission="android.permission.BIND_INPUT_METHOD"> <meta-data android:name="android.view.im" android:resource="@xml/method" /> </service> ``` 上面的代码声明了一个名为 CustomKeyboard 的服务,并将其与 android.view.im 绑定。在 res/xml 目录下创建一个名为 method.xml 的文件,用于指定 CustomKeyboard 的布局和行为: ```xml <?xml version="1.0" encoding="utf-8"?> <input-method xmlns:android="http://schemas.android.com/apk/res/android" android:settingsActivity=".SettingsActivity" android:imeSubtypeLocale="en_US" android:imeSubtypeMode="keyboard" > </input-method> ``` 上面的代码指定了键盘的设置活动、语言环境和子类型模式。 2. 创建 CustomKeyboard 类,并继承 InputMethodService。在这个类中,你需要重写一些回调方法,例如 onCreateInputView()、onKeyDown() 和 onStartInputView() 等。这些方法将决定键盘的外观和行为。 ```java public class CustomKeyboard extends InputMethodService implements KeyboardView.OnKeyboardActionListener { private KeyboardView keyboardView; private Keyboard keyboard; @Override public View onCreateInputView() { keyboardView = (KeyboardView) getLayoutInflater().inflate(R.layout.keyboard, null); keyboard = new Keyboard(this, R.xml.qwerty); keyboardView.setKeyboard(keyboard); keyboardView.setOnKeyboardActionListener(this); return keyboardView; } @Override public void onStartInputView(EditorInfo info, boolean restarting) { super.onStartInputView(info, restarting); keyboardView.setPreviewEnabled(false); } @Override public void onKey(int primaryCode, int[] keyCodes) { InputConnection ic = getCurrentInputConnection(); switch (primaryCode) { case Keyboard.KEYCODE_DELETE: ic.deleteSurroundingText(1, 0); break; case Keyboard.KEYCODE_SHIFT: // do something break; default: char c = (char) primaryCode; ic.commitText(String.valueOf(c), 1); } } } ``` 上面的代码创建了一个名为 CustomKeyboard 的类,并在 onCreateInputView() 方法中设置了键盘的布局和行为。在 onStartInputView() 方法中,我们禁用了键盘预览功能。在 onKey() 方法中,我们检查按下的键码并执行相应的操作。 3. 创建键盘布局。在 res/xml 目录下创建一个名为 qwerty.xml 的文件,用于指定键盘布局: ```xml <?xml version="1.0" encoding="utf-8"?> <Keyboard xmlns:android="http://schemas.android.com/apk/res/android" android:keyWidth="10%p" android:keyHeight="60dp" android:horizontalGap="0px" android:verticalGap="0px" android:keyEdgeFlags="left"> <Row> <Key android:keyLabel="q" android:keyEdgeFlags="left"/> <Key android:keyLabel="w"/> <Key android:keyLabel="e"/> <Key android:keyLabel="r"/> <Key android:keyLabel="t"/> <Key android:keyLabel="y"/> <Key android:keyLabel="u"/> <Key android:keyLabel="i"/> <Key android:keyLabel="o"/> <Key android:keyLabel="p" android:keyEdgeFlags="right"/> </Row> <Row> <Key android:keyLabel="a" android:keyEdgeFlags="left"/> <Key android:keyLabel="s"/> <Key android:keyLabel="d"/> <Key android:keyLabel="f"/> <Key android:keyLabel="g"/> <Key android:keyLabel="h"/> <Key android:keyLabel="j"/> <Key android:keyLabel="k"/> <Key android:keyLabel="l android:keyEdgeFlags="right"/> </Row> <Row> <Key android:keyLabel="shift" android:horizontalGap="10%p" android:keyWidth="20%p" android:keyEdgeFlags="left" android:isModifier="true" android:isSticky="true"/> <Key android:keyLabel="z"/> <Key android:keyLabel=""/> <Key android:keyLabel="c"/> <Key android:keyLabel="v"/> <Key android:keyLabel="b"/> <Key android:keyLabel="n"/> <Key android:keyLabel="m"/> <Key android:keyLabel="delete" android:keyWidth="20%p" android:keyEdgeFlags="right" android:icon="@drawable/ic_delete"/> </Row> <Row> <Key android:keyLabel="123" android:keyEdgeFlags="left" android:keyWidth="20%p"/> <Key android:keyLabel=" " android:keyWidth="40%p"/> <Key android:keyLabel="return" android:keyWidth="20%p" android:keyEdgeFlags="right"/> </Row> </Keyboard> ``` 上面的代码指定了一个基本的 QWERTY 键盘布局,包含字母、数字和删除键。 4. 运行应用程序并测试自定义软键盘。在测试键盘时,你需要在 Android 设备的输入法设置中激活你的自定义键盘。 以上就是创建自定义软键盘的基本步骤,你可以根据需要修改键盘的布局和行为。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值