Android 自定义软键盘遇到的问题

首先来分析一下软键盘的基本属性
- 软键盘的实现
- 点击输入框从底部弹出软键盘
- 弹出软键盘后焦点在输入框
- 弹出软键盘不遮挡输入框

软键盘的实现
可以使用KeyboardView也可以自己写布局写点击事件(除特殊情况不推荐)
KeyboardView的简单实现方法
一、在res下新建xml文件夹,在xml文件夹中新建keyboard.xml文件

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
          android:keyWidth="33.3333%p" android:horizontalGap="0px"
          android:verticalGap="0px" android:keyHeight="80dp">
    <Row>
        <Key android:codes="55" android:keyLabel="7" />
        <Key android:codes="56" android:keyLabel="8" />
        <Key android:codes="57" android:keyLabel="9" android:keyEdgeFlags="right"/>
    </Row>
    <Row>
        <Key android:codes="52" android:keyLabel="4" />
        <Key android:codes="53" android:keyLabel="5" />
        <Key android:codes="54" android:keyLabel="6" android:keyEdgeFlags="right"/>

    </Row>
    <Row>
        <Key android:codes="49" android:keyLabel="1" />
        <Key android:codes="50" android:keyLabel="2" />
        <Key android:codes="51" android:keyLabel="3" android:keyEdgeFlags="right"/>
    </Row>
    <Row>
        <Key android:codes="46" android:keyLabel="." />
        <Key android:codes="48" android:keyLabel="0" />
        <Key android:codes="-3" android:keyEdgeFlags="right" android:keyLabel="OK"/>
    </Row>

</Keyboard>

二、这个地方有的实现有点不一样,一般来说不应该在每一个布局里都加入KeyboardViw,比如我使用的在MainActivity,Main里面全是fragment所以就直接在布局里面了

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/img_bg">

    <FrameLayout
        android:id="@+id/frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingTop="50dp">

    </FrameLayout>

    <android.inputmethodservice.KeyboardView
        android:id="@+id/keyboardview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/write"
        android:layout_alignParentBottom="true"
        android:focusable="true"
        android:usableInTouchMode="true"
        android:visibility="invisible"/>
</RelativeLayout>

然后

import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.inputmethodservice.InputMethodService;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.media.AudioManager;
import android.text.Editable;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.InputConnection;
import android.widget.EditText;

import com.kubu.terminal.R;

import java.util.List;

import static android.content.Context.AUDIO_SERVICE;

/**
 * Created by steven on 2017/7/31.
 */

public class KeyBoradUtil extends InputMethodService implements KeyboardView.OnKeyboardActionListener
{
    private Context mContext;//上下文对象
    private KeyboardView mKeyboardView;
    private Keyboard mKeyboard;
    private EditText mEdit;

    /**
     * 必须activity作为上下文对像 *
     *
     * @param context
     */
    public KeyBoradUtil(Context context)
    {
        mContext = context;
        //初始化键盘布局,下面在放进 KeyBoardView里面去。
        mKeyboard = new Keyboard(mContext, R.xml.keyboard);
        //配置keyBoardView
        try
        {
            mKeyboardView = (KeyboardView) ((Activity)mContext).findViewById(R.id.keyboardview);
            mKeyboardView.setKeyboard(mKeyboard); //设置键盘
            mKeyboardView.setEnabled(true);
            mKeyboardView.setPreviewEnabled(false);   //这个是,效果图按住是出来的预览图。

            //设置监听,不设置的话会报错。监听放下面了。
            mKeyboardView.setOnKeyboardActionListener(this);
        } catch (Exception e)
        {
            Log.e("sun", "keyview初始化失败");
        }
    }

    public void setEdit(EditText mEdit)
    {
        this.mEdit = mEdit;
    }


    @Override
    public void onPress(int primaryCode)
    {

    }

    @Override
    public void onRelease(int primaryCode)
    {

    }

    @Override
    public void onKey(int primaryCode, int[] keyCodes)
    {
        Editable editable = mEdit.getText();
        int start = mEdit.getSelectionStart();
        if (primaryCode == Keyboard.KEYCODE_CANCEL)
        {// 完成
            hideKeyboard();
        } else if (primaryCode == Keyboard.KEYCODE_DELETE)
        {// 回退
            if (editable != null && editable.length() > 0)
            {
                if (start > 0)
                {
                    editable.delete(start - 1, start);
                }
            }
        } else if (primaryCode == 57419)
        { // go left
            if (start > 0)
            {
                mEdit.setSelection(start - 1);
            }
        } else if (primaryCode == 57421)
        { // go right
            if (start < mEdit.length())
            {
                mEdit.setSelection(start + 1);
            }
        } else
        {
            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 void showKeyboard()
    {
        int visibility = mKeyboardView.getVisibility();
        if (visibility == View.GONE || visibility == View.INVISIBLE)
        {
            mKeyboardView.setVisibility(View.VISIBLE);
            int hight = mKeyboardView.getHeight();

            Log.d("TAG",hight+"");
            ObjectAnimator bad = ObjectAnimator.ofFloat(mKeyboardView, "translationY", hight, 0);
            bad.setDuration(300);
            bad.start();
        }
    }

    //关闭软键盘
    public void hideKeyboard()
    {
        int visibility = mKeyboardView.getVisibility();
        if (visibility == View.VISIBLE)
        {
            int hight = mKeyboardView.getHeight();
            ObjectAnimator bad = ObjectAnimator.ofFloat(mKeyboardView, "translationY", 0, hight);
            bad.setDuration(300);
            bad.start();
            bad.addListener(new Animator.AnimatorListener()
            {
                @Override
                public void onAnimationStart(Animator animation)
                {

                }

                @Override
                public void onAnimationEnd(Animator animation)
                {
                    mKeyboardView.setVisibility(View.INVISIBLE);
                }

                @Override
                public void onAnimationCancel(Animator animation)
                {

                }

                @Override
                public void onAnimationRepeat(Animator animation)
                {

                }
            });
        }
    }
}

注意在布局里KeyboardView的android:visibility=”invisible”不能为gone,否则getHeight()为空 ,然后初始化 mKeyBoard = new KeyBoradUtil(getActivity()),并在editText的setOnTouchListener里面显示软键盘。

    @Override
    public boolean onTouch(View v, MotionEvent event)
    {
        switch (v.getId())
        {
            case R.id.et_phone:
                //隐藏系统软键盘
                setInputType(et_phone);
                mKeyBoard.setEdit(et_phone);
                break;
            case R.id.et_password:
                //隐藏系统软键盘
                setInputType(et_password);
                mKeyBoard.setEdit(et_password);
                break;
        }

       mKeyBoard.showKeyboard();
        return false;
    }

    private void setInputType(EditText editText)
    {
        if (android.os.Build.VERSION.SDK_INT <= 10)
        {//4.0以下 danielinbiti
            editText.setInputType(InputType.TYPE_NULL);
        } else
        {
            getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
            try
            {
                Class<EditText> cls = EditText.class;
                Method setShowSoftInputOnFocus = cls.getMethod("setShowSoftInputOnFocus", boolean.class);
                setShowSoftInputOnFocus.setAccessible(true);
                setShowSoftInputOnFocus.invoke(editText, false);
            } catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }

像我上面说的整个工程就一个Activity,初始化以及显示都在那一个Activity里面,那么如果不是这样的呢,额…,想过使用PopupWindows,但是PopupWindows弹出后,输入框的光标没有了(⊙﹏⊙),而且点返回按钮的时候只是仅仅关闭弹窗(跟实际软键盘效果不符,可能有其他处理方法,感觉没意义),然后又想到用addView的方式加进去,又发现不同布局可能最外层可能不一样,没法统一处理,目前没找到好的解决办法。

最后不遮挡输入框的做法,很简单,我们知道了软键盘的高度,那么通过一系列的计算通过view.scrollTo(0,editH-keyboardH+10);移动布局就行了,具体看代码

为了拿到View,我在KeyBoradUtil中加了个setView()

public void setView(View view){
        this.view = view;
}
 public void showKeyboard()
 {
        //计算输入框底部到父布局顶部的距离,有50dp的padding
        int editH = mEdit.getBottom()+DisplayUtil.dip2px(mContext,50);
        //计算软键盘顶部到父布局顶部的距离
        int keyboardH = mKeyboardView.getTop();
        //移动布局
        if (editH>keyboardH)
        {
            if (view != null)
            {
                //加了10的偏移,看个人爱好,可以不加
                view.scrollTo(0,editH-keyboardH+10);
            }
        }

        int visibility = mKeyboardView.getVisibility();
        if (visibility == View.GONE || visibility == View.INVISIBLE)
        {
            mKeyboardView.setVisibility(View.VISIBLE);
            int hight = mKeyboardView.getHeight();

            Log.d("TAG",hight+"");
            ObjectAnimator bad = ObjectAnimator.ofFloat(mKeyboardView, "translationY", hight, 0);
            bad.setDuration(200);
            bad.start();
        }
 }
 public void hideKeyboard()
 {
        int visibility = mKeyboardView.getVisibility();
        if (visibility == View.VISIBLE)
        {
            if (view != null)
            {
                //布局恢复
                view.scrollTo(0,0);
            }

            int hight = mKeyboardView.getHeight();
            ObjectAnimator bad = ObjectAnimator.ofFloat(mKeyboardView, "translationY", 0, hight);
            bad.setDuration(200);
            bad.start();
            bad.addListener(new Animator.AnimatorListener()
            {
                @Override
                public void onAnimationStart(Animator animation)
                {

                }

                @Override
                public void onAnimationEnd(Animator animation)
                {
                    mKeyboardView.setVisibility(View.INVISIBLE);
                }

                @Override
                public void onAnimationCancel(Animator animation)
                {

                }

                @Override
                public void onAnimationRepeat(Animator animation)
                {

                }
            });
        }
 }

猜你喜欢

转载自blog.csdn.net/a598068693/article/details/76502396