1. 程式人生 > >Android監聽軟鍵盤開啟收起事件

Android監聽軟鍵盤開啟收起事件

一:瞭解軟鍵盤上各類鍵名:

電話鍵

鍵名 描述 鍵值
KEYCODE_CALL 撥號鍵 5
KEYCODE_ENDCALL 掛機鍵 6
KEYCODE_HOME 按鍵Home 3
KEYCODE_MENU 選單鍵 82
KEYCODE_BACK 返回鍵 4
KEYCODE_SEARCH 搜尋鍵 84
KEYCODE_CAMERA 拍照鍵 27
KEYCODE_FOCUS 拍照對焦鍵 80
KEYCODE_POWER 電源鍵 26
KEYCODE_NOTIFICATION 通知鍵 83
KEYCODE_MUTE 話筒靜音鍵 91
KEYCODE_VOLUME_MUTE 揚聲器靜音鍵 164
KEYCODE_VOLUME_UP 音量增加鍵 24
KEYCODE_VOLUME_DOWN 音量減小鍵 25

控制鍵

鍵名 描述 鍵值
KEYCODE_ENTER 回車鍵 66
KEYCODE_ESCAPE ESC鍵 111
KEYCODE_DPAD_CENTER 導航鍵 確定鍵 23
KEYCODE_DPAD_UP 導航鍵 向上 19
KEYCODE_DPAD_DOWN 導航鍵 向下 20
KEYCODE_DPAD_LEFT 導航鍵 向左 21
KEYCODE_DPAD_RIGHT 導航鍵 向右 22
KEYCODE_MOVE_HOME 游標移動到開始鍵 122
KEYCODE_MOVE_END 游標移動到末尾鍵 123
KEYCODE_PAGE_UP 向上翻頁鍵 92
KEYCODE_PAGE_DOWN 向下翻頁鍵 93
KEYCODE_DEL 退格鍵 67
KEYCODE_FORWARD_DEL 刪除鍵 112
KEYCODE_INSERT 插入鍵 124
KEYCODE_TAB Tab鍵 61
KEYCODE_NUM_LOCK 小鍵盤鎖 143
KEYCODE_CAPS_LOCK 大寫鎖定鍵 115
KEYCODE_BREAK Break/Pause鍵 121
KEYCODE_SCROLL_LOCK 滾動鎖定鍵 116
KEYCODE_ZOOM_IN 放大鍵 168
KEYCODE_ZOOM_OUT 縮小鍵 169

二:四種收起軟鍵盤的方式

1、點選軟鍵盤右下角的Return按鈕(系統收起)

editText.setOnEditorActionListener(new OnEditorActionListener() {
@Override
public boolean onEditorAction(final TextView v, final int actionId, final KeyEvent event) {
    // 可捕捉右下角的Return按鈕
    //新增丟擲收起事件程式碼
    return false;
    }
});

2、輸入框焦點時按返回按鈕(系統收起)

editText.setOnKeyListener(new OnKeyListener() {   
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
//keyCode == KeyEvent.KEYCODE_ENTER  回車鍵
        //一般執行收起鍵盤操作
        //...
        return true;
    }
    return false;
    }
});

開啟鍵盤和收起鍵盤程式碼:

    /**
     * 開啟鍵盤.
     *
     * @param context the context
     */
    public static void showSoftInput(Context context) {
        InputMethodManager inputMethodManager = (InputMethodManager) context
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        inputMethodManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
    }

    /**
     * 關閉鍵盤事件.
     *
     * @param context the context
     */
    public static void closeSoftInput(Context context) {
        InputMethodManager inputMethodManager = (InputMethodManager) context
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        if (inputMethodManager != null && ((Activity) context).getCurrentFocus() != null) {
            inputMethodManager.hideSoftInputFromWindow(((Activity) context).getCurrentFocus()
                    .getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }

3、點選軟鍵盤和輸入框的外部

給輸入框的父容器增加觸控監聽
@Override
public boolean onTouchEvent(MotionEvent event) {

    if (indexOfChild(editText) > -1) {
    // 新增收起鍵盤方法
    }
return super.onTouchEvent(event);
}

4、點選軟鍵盤自帶的收起按鈕(軟鍵盤收起)

注:一般介面銷燬時需要移除軟鍵盤上的監聽

1)Activity:

public class SoftKeyboardActivity extends AppCompatActivity implements SoftKeyboardStateHelper.SoftKeyboardStateListener{

    private SoftKeyboardStateHelper softKeyboardStateHelper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_soft_keyboard);
        initView();
    }

    private void initView() {
        softKeyboardStateHelper = new SoftKeyboardStateHelper(this);
        softKeyboardStateHelper.addSoftKeyboardStateListener(this);
    }

    @Override
    public void onSoftKeyboardOpened(int keyboardHeightInPx) {
        Toast.makeText(SoftKeyboardActivity.this, "鍵盤開啟", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onSoftKeyboardClosed() {
        Toast.makeText(SoftKeyboardActivity.this, "鍵盤關閉", Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        softKeyboardStateHelper.removeSoftKeyboardStateListener(this);
    }
}

2)佈局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:fitsSystemWindows="true"
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/lin_01"
        android:layout_width="fill_parent"
        android:layout_height="40dp"
        android:layout_margin="20dp"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/edit_01"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_marginRight="8dp"
            android:layout_weight="1"
            android:background="@drawable/details_set_a"
            android:gravity="center_vertical"
            android:paddingLeft="8dp"
            android:textCursorDrawable="@drawable/color_cursor" />
        <!-- android:textCursorDrawable="@drawable/color_cursor" -->
        <!-- 游標顏色 -->

        <TextView
            android:id="@+id/tv_01"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:background="@drawable/collection_bg02"
            android:gravity="center"
            android:text="新增" />
    </LinearLayout>
    <TextView
        android:layout_width="match_parent"
        android:layout_weight="1"
        android:layout_height="match_parent" />
</LinearLayout>

3)自定義的軟鍵盤自帶的收起:

import android.app.Activity;
import android.graphics.Rect;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;

import java.util.LinkedList;
import java.util.List;

/**
 * 自定義軟鍵盤自帶的收起控制
 * Created by ${Dota.Wang} on 2017/12/11.
 */
public class SoftKeyboardStateHelper implements ViewTreeObserver.OnGlobalLayoutListener {
    private  View activityRootView;
    private int   lastSoftKeyboardHeightInPx;
    private boolean isSoftKeyboardOpened;
    private int height ;//控制軟鍵盤開啟時機

    public interface SoftKeyboardStateListener {
        void onSoftKeyboardOpened(int keyboardHeightInPx);
        void onSoftKeyboardClosed();
    }

    private final List<SoftKeyboardStateListener> listeners = new LinkedList<SoftKeyboardStateListener>();


    public SoftKeyboardStateHelper(Activity contextObj) {
        if (contextObj == null) {
            Log.i("dota", "contextObj is null");
            return;
        }
        activityRootView = findContentView(contextObj);
        if (activityRootView!=null){
            activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(this);
        }
//        this(activityRootView, false);
    }

    public SoftKeyboardStateHelper(Activity contextObj, boolean isSoftKeyboardOpened) {
        if (contextObj == null) {
            Log.i("dota", "contextObj is null");
            return;
        }
        activityRootView = findContentView(contextObj);
        if (activityRootView!=null){
            activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(this);
        }
//        this.activityRootView     = activityRootView;
//        this.isSoftKeyboardOpened = isSoftKeyboardOpened;
    }

    private View findContentView(Activity contextObj) {
        return contextObj.findViewById(android.R.id.content);
    }

    @Override
    public void onGlobalLayout() {
        final Rect r = new Rect();
        activityRootView.getWindowVisibleDisplayFrame(r);

        final int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
        if (screenHeight == 1920){
            height = 200;
        }else {
            height = 100;
        }
        if (!isSoftKeyboardOpened && heightDiff > height ) { // if more than 100 pixels, its probably a keyboard...
            isSoftKeyboardOpened = true;
            notifyOnSoftKeyboardOpened(heightDiff);
        } else if (isSoftKeyboardOpened && heightDiff < height ) {
            isSoftKeyboardOpened = false;
            notifyOnSoftKeyboardClosed();
        }
    }

    public void setIsSoftKeyboardOpened(boolean isSoftKeyboardOpened) {
        this.isSoftKeyboardOpened = isSoftKeyboardOpened;
    }

    public boolean isSoftKeyboardOpened() {
        return isSoftKeyboardOpened;
    }

    /**
     * Default value is zero (0)
     * @return last saved keyboard height in px
     */
    public int getLastSoftKeyboardHeightInPx() {
        return lastSoftKeyboardHeightInPx;
    }

    public void addSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
        listeners.add(listener);
    }

    public void removeSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
        listeners.remove(listener);
    }

    private void notifyOnSoftKeyboardOpened(int keyboardHeightInPx) {
        this.lastSoftKeyboardHeightInPx = keyboardHeightInPx;

        for (SoftKeyboardStateListener listener : listeners) {
            if (listener != null) {
                listener.onSoftKeyboardOpened(keyboardHeightInPx);
            }
        }
    }

    private void notifyOnSoftKeyboardClosed() {
        for (SoftKeyboardStateListener listener : listeners) {
            if (listener != null) {
                listener.onSoftKeyboardClosed();
            }
        }
    }
}

三:EditText被底部固定欄擋住,使用AndroidBug5497Workaround出現相容問題

一般這類問題出現在華為手機上比較多,如榮耀手機

解決方法如下:

import android.app.Activity;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;

/**
 * Created by Administrator on 2017/12/8.
 */
public class AndroidBug5497Workaround {

    // For more information, see https://code.google.com/p/android/issues/detail?id=5497
    // To use this class, simply invoke assistActivity() on an Activity that already has its content view set.

    public static void assistActivity (Activity activity) {
        new AndroidBug5497Workaround(activity);
    }

    private View mChildOfContent;
    private int usableHeightPrevious;
    private FrameLayout.LayoutParams frameLayoutParams;

    private AndroidBug5497Workaround(Activity activity) {
        FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
        mChildOfContent = content.getChildAt(0);
        mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            public void onGlobalLayout() {
                possiblyResizeChildOfContent();
            }
        });
        frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
    }

    private void possiblyResizeChildOfContent() {
        int usableHeightNow = computeUsableHeight();
        if (usableHeightNow != usableHeightPrevious) {
            int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
            int heightDifference = usableHeightSansKeyboard - usableHeightNow;
            if (heightDifference > (usableHeightSansKeyboard/4)) {
                // keyboard probably just became visible
                frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
            } else {
                // keyboard probably just became hidden
                frameLayoutParams.height = usableHeightSansKeyboard;
            }
            mChildOfContent.requestLayout();
            usableHeightPrevious = usableHeightNow;
        }
    }

    private int computeUsableHeight() {
        Rect r = new Rect();
        mChildOfContent.getWindowVisibleDisplayFrame(r);
        return (r.bottom);// 全屏模式下: return r.bottom
    }

}

使用起來很容易,在你的setContentView 之後呼叫:

AndroidBug5497Workaround.assistActivity(this);

此時可能還會出現問題,可以嘗試在該Activity的AndroidManifest中新增屬性

android:windowSoftInputMode="adjustResize"

如果在新增完該屬性還會出現全屏和adjustResize的衝突,就嘗試用Plan B

完美解決問題 相容多種手機

參考文件: