監聽軟鍵盤的彈出與收起(近乎完美)

監聽軟鍵盤的彈出與收起的實現方法

由於這週末單休,然後,然後,然後 我一個不小心幾乎是睡了一天,深感恐怖,於是我覺得我得做點什麼,就想到了前幾天兩個羣友問的關於軟鍵盤的問題,正好我之前在工作中處理過,所以便寫個博客記錄分享一下

在這裏,我寫兩個實現的方法。

1.是利用OnLayoutChangeListener的監聽,在這裏我簡單的說下過程,因爲應羣友大大的建議,寫的註釋還是挺多的,也比較簡單 。

思路的話就是點擊控件彈出軟鍵盤,然後輸入,點擊添加則隱藏佈局同時收起鍵盤,但是考慮到用戶可能點擊返回鍵,軟鍵盤的收起鍵,關於返回鍵的話,我們可以監聽實現,但是軟鍵盤的收起鍵,我 我 我 還不知道(我只是個萌新,有知道的小夥子望告知一下子),但是這樣要寫3個監聽比較繁瑣,這時候就覺得要是找個軟鍵盤監聽的方法就好了,還是一樣 關於軟鍵盤監聽的方法呢 我還是不知道,應該是沒有。所以我這裏是利用OnLayoutChangeListener監聽佈局間接實現的

下面直接上代碼 MainActivity .java

public class MainActivity extends Activity implements View.OnLayoutChangeListener, View.OnClickListener {
    Button btn_name,btn_01;
    // 開始寫輸入法彈出的
    private LinearLayout lin_01;
    private EditText edit_01;
    private TextView tv_01;
    // 顯示隱藏鍵盤用的
    InputMethodManager m;
    // 屏幕高度
    private int screenHeight = 0;
    // 軟件盤彈起後所佔高度閥值
    private int keyHeight = 0;

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

    private void initView() {
        btn_name = (Button) findViewById(R.id.btn_name);
        btn_01 = (Button) findViewById(R.id.btn_01);
        lin_01 = (LinearLayout) findViewById(R.id.lin_01);
        edit_01 = (EditText) findViewById(R.id.edit_01);
        tv_01 = (TextView) findViewById(R.id.tv_01);
        // 實例化顯示隱藏鍵盤用的,當前顯示則隱藏,當前隱藏則顯示
        m = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        tv_01.setOnClickListener(this);
        btn_name.setOnClickListener(this);
        btn_01.setOnClickListener(this);
        // 獲取屏幕高度
        screenHeight = this.getWindowManager().getDefaultDisplay().getHeight();
        // 閥值設置爲屏幕高度的1/3
        keyHeight = screenHeight / 3;
    }

    // 監聽軟鍵盤彈出收起的
    @Override
    public void onLayoutChange(View v, int left, int top, int right,
                               int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
        // old是改變前的左上右下座標點值,沒有old的是改變後的左上右下座標點值
        // 現在認爲只要控件將Activity向上推的高度超過了1/3屏幕高,就認爲軟鍵盤彈起
        if (oldBottom != 0 && bottom != 0 && (oldBottom - bottom > keyHeight)) {
            Log.e("onLayoutChange===","監聽到軟鍵盤彈起");
            APP.mToast("監聽到軟鍵盤彈起");
            // 監聽到軟鍵盤彈起
        } else if (oldBottom != 0 && bottom != 0
                && (bottom - oldBottom > keyHeight)) {
            lin_01.setVisibility(View.GONE);
            // 失去焦點
            edit_01.setFocusable(false);
            edit_01.setFocusableInTouchMode(false);
            edit_01.setText("");
            Log.e("onLayoutChange===","監聽到軟件盤關閉");
            APP.mToast("監聽到軟件盤關閉");
            // 監聽到軟件盤關閉
        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_name:
                // 點擊添加按鈕的代碼
                // 顯示隱藏鍵盤用的,當前顯示則隱藏,當前隱藏則顯示
                m.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
                lin_01.setVisibility(View.VISIBLE);
                // 獲取焦點
                edit_01.setFocusable(true);
                edit_01.setFocusableInTouchMode(true);
                // 顯示光標
                edit_01.requestFocus();// 獲取焦點 光標出現
                break;
            case R.id.tv_01:
                String edit_tian = edit_01.getText().toString().trim();
                if (!APP.NotNull(edit_tian)) {
                    APP.mToast("請輸入");
                    return;
                }
                // 顯示隱藏鍵盤用的,當前顯示則隱藏,當前隱藏則顯示
                m.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
                APP.mToast(edit_tian);
                break;
            case R.id. btn_01:
             startActivity(new Intent(MainActivity.this,KeyBoardActivity.class));
                break;

        }
    }
    @Override
    public void onResume() {
        super.onResume();
        // 添加layout大小發生改變監聽器
        lin_01.addOnLayoutChangeListener(this);
    }

這裏寫圖片描述

這裏是主要代碼,因爲常規來說輸入法彈出的話高度是超過屏幕的1/3的,所以我們就以此判斷,當然也不一定完全正確。歡迎提供更好的方法哦


順便貼一下佈局 activity_main.xml;

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:clipToPadding="true"
    android:fillViewport="true"
    android:fitsSystemWindows="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:padding="15dp"
            android:text="軟鍵盤監聽"
            android:textSize="20sp" />

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent">

            <ScrollView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="#ffffff">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:gravity="center"
                    android:orientation="vertical">

                    <Button
                        android:id="@+id/btn_name"
                        android:text="點擊彈出軟鍵盤"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true" />
                    <Button
                        android:id="@+id/btn_01"
                        android:text="點擊跳轉"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true" />
                    <Button
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true" />
                    <Button
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true" />
                    <Button
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true" />
                    <Button
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true" />
                    <Button
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true" />
                    <Button
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true" />
                    <Button
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true" />
                    <Button
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true" />
                    <Button
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true" />
                    <Button
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true" />
                    <Button
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true" />
                    <Button
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true" />
                    <Button
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true" />
                    <Button
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true" />
                    <Button
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerInParent="true" />
                </LinearLayout>

            </ScrollView>

            <LinearLayout
                android:id="@+id/lin_01"
                android:layout_width="fill_parent"
                android:layout_height="40dp"
                android:layout_alignParentBottom="true"
                android:layout_marginBottom="3dp"
                android:layout_marginLeft="8dp"
                android:layout_marginRight="8dp"
                android:orientation="horizontal"
                android:visibility="gone">

                <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>
        </RelativeLayout>
    </LinearLayout>

</RelativeLayout>

2.是使用自定義佈局,頁面佈局中包含ScrollVIew,在軟鍵盤彈起後,佈局的高度會發生改變,根據佈局的高度來判斷軟鍵盤的狀態。(無意中大大神博客中見到的,於是實現了下)

思路其實也差不多,都是根據佈局底部高度來判斷佈局是否上移,主要代碼都在onLayout中

下面直接上代碼 KeyBoardActivity.java

public class KeyBoardActivity extends Activity {

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

    private void initView() {
        KeyboardLayout mainView = (KeyboardLayout) findViewById(R.id.keyboardLayout1);
        final TextView tv = (TextView) findViewById(R.id.testone_tv);
        mainView.setOnkbdStateListener(new KeyboardLayout.onKybdsChangeListener() {

            public void onKeyBoardStateChange(int state) {
                switch (state) {
                    case KeyboardLayout.KEYBOARD_STATE_HIDE:
                        tv.setVisibility(View.VISIBLE);
                        APP.mToast("軟鍵盤隱藏");
                        break;
                    case KeyboardLayout.KEYBOARD_STATE_SHOW:
                        tv.setVisibility(View.INVISIBLE);
                        APP.mToast("軟鍵盤彈起");
                        break;
                }
            }
        });
    }
}

接下來是自定義的類,註釋已經加在代碼中了,應該不需要過多的解釋了 KeyboardLayout.java

/**
 * Created by 搬磚小能手 on 2017/4/24.
 * 介紹:這個是自定義的佈局,自定義佈局可以繼承各種常見佈局。自定義佈局有鍵盤狀態改變監聽器,可以通過註冊監聽器來監聽軟鍵盤狀態。
 */

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.RelativeLayout;

public class KeyboardLayout extends RelativeLayout {
    private static final String TAG = KeyboardLayout.class.getSimpleName();
    public static final byte KEYBOARD_STATE_SHOW = -3;//軟鍵盤彈起
    public static final byte KEYBOARD_STATE_HIDE = -2;//軟鍵盤隱藏
    public static final byte KEYBOARD_STATE_INIT = -1;//初始
    private boolean mHasInit;
    private boolean mHasKeybord;
    private int mHeight;
    private onKybdsChangeListener mListener;

    public KeyboardLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

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

    public KeyboardLayout(Context context) {
        super(context);
    }
    /**
     * 設置鍵盤狀態監聽器
     */
    public void setOnkbdStateListener(onKybdsChangeListener listener){
        mListener = listener;
    }
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if (!mHasInit) {
            mHasInit = true;
            mHeight = b;//獲取底部高度
            if (mListener != null) {//初始狀態
                mListener.onKeyBoardStateChange(KEYBOARD_STATE_INIT);
            }
        } else {
            mHeight = mHeight < b ? b : mHeight;
        }
        if (mHasInit && mHeight > b) {//大於則表示佈局本遮擋或頂起
            mHasKeybord = true;
            if (mListener != null) {//彈出
                mListener.onKeyBoardStateChange(KEYBOARD_STATE_SHOW);
            }
            Log.w(TAG, "show keyboard.......");
        }
        if (mHasInit && mHasKeybord && mHeight == b) {//佈局曾被遮擋或頂起,且回到了初始高度
            mHasKeybord = false;
            if (mListener != null) {//收起
                mListener.onKeyBoardStateChange(KEYBOARD_STATE_HIDE);
            }
            Log.w(TAG, "hide keyboard.......");
        }
    }

    public interface onKybdsChangeListener{
        public void onKeyBoardStateChange(int state);
    }
}

主要代碼都在onLayout中,註釋也都有,主要就是獲得佈局初始高度於之後的對比

按照國際慣例,下面就是佈局了 activity_keyboard.xml;

<com.mykeyboard.KeyboardLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/keyboardLay"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:fillViewport="true" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/tv_content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="#ffffff"
                android:gravity="center"
                android:text="軟件盤彈起,我INVISIBLE!軟鍵盤隱藏,我VISIBLE!"
                android:layout_weight="1.0"
                android:textColor="#000000"
                android:textStyle="bold" />

            <LinearLayout
                android:id="@+id/lin_01"
                android:layout_width="fill_parent"
                android:layout_height="40dp"
                android:layout_alignParentBottom="true"
                android:layout_marginBottom="3dp"
                android:layout_marginLeft="8dp"
                android:layout_marginRight="8dp"
                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>

        </LinearLayout>
    </ScrollView>

</com.mykeyboard.KeyboardLayout>

最後來一波Demo:點擊跳轉至下載

到這裏也就結束了 ,我也休息去了,明天早上還要參加史詩級災難片演出呢,嘿嘿
另外需要學習小夥伴可以加羣!大家一起討論哈哈!一起開車!本萌新推薦力推啊。羣號:188089649!


上午又擼了一發,於是發現一種方法,在這裏更新一下

利用的是ViewTreeObserver一個的內部接口實現的,在這裏簡單介紹一下

1. interface ViewTreeObserver.OnGlobalFocusChangeListener
當在一個視圖樹中的焦點狀態發生改變時,所要調用的回調函數的接口類

2. interface ViewTreeObserver.OnGlobalLayoutListener
當在一個視圖樹中全局佈局發生改變或者視圖樹中的某個視圖的可視狀態發生改變時,所要調用的回調函數的接口類

3. interface ViewTreeObserver.OnPreDrawListener
當一個視圖樹將要繪製時,所要調用的回調函數的接口類

4. interface ViewTreeObserver.OnScrollChangedListener
當一個視圖樹中的一些組件發生滾動時,所要調用的回調函數的接口類

5. interface ViewTreeObserver.OnTouchModeChangeListener
當一個視圖樹的觸摸模式發生改變時,所要調用的回調函數的接口類

這裏的話,我們可以利用OnGlobalLayoutListener來獲得一個視圖的真實高度。

但是需要注意的是OnGlobalLayoutListener可能會被多次觸發,因此在得到了高度之後,要將OnGlobalLayoutListener註銷掉。
原理的話和上面的也是大同小異,就不多作解釋了,就直接上代碼了


GlobalLayoutActivity.java

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.mykeyboard.R;
import com.mykeyboard.app.APP;
import com.mykeyboard.widget.KeyboardChangeListener;

/**
 * abc
 * Created by 搬磚小能手 on 2017/4/24.
 * E-mail:[email protected].
 * Signature:當你的才華滿足不了你的野心的時候,那麼你應該靜下心來學習.
 * Alert:語言的巨人,行動的矮子!
 */
public class GlobalLayoutActivity extends Activity implements KeyboardChangeListener.KeyBoardListener{
    private KeyboardChangeListener mKeyboardChangeListener;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_globallayout);
        initView();
    }
    private void initView(){
        mKeyboardChangeListener = new KeyboardChangeListener(this);
        mKeyboardChangeListener.setKeyBoardListener(this);
    }

    @Override
    public void onKeyboardChange(boolean isShow, int keyboardHeight) {
        Log.d("GlobalLayoutActivity==", "onKeyboardChange() called with: " + "isShow = [" + isShow + "], keyboardHeight = [" + keyboardHeight + "]");
        APP.mToast("軟鍵盤="+isShow+",高度差=keyboardHeight=="+keyboardHeight);
    }
}

這裏的話比較簡單,沒啥要注意的,主要是KeyboardChangeListener中,

KeyboardChangeListener.java

public class KeyboardChangeListener implements ViewTreeObserver.OnGlobalLayoutListener {
    private static final String TAG = "ListenerHandler";
    private View mContentView;
    private int mOriginHeight;
    private int mPreHeight;
    private KeyBoardListener mKeyBoardListen;

    public interface KeyBoardListener {
        /**
         * call back
         * @param isShow true is show else hidden
         * @param keyboardHeight keyboard height
         */
        void onKeyboardChange(boolean isShow, int keyboardHeight);
    }

    public void setKeyBoardListener(KeyBoardListener keyBoardListen) {
        this.mKeyBoardListen = keyBoardListen;
    }

    public KeyboardChangeListener(Activity contextObj) {
        if (contextObj == null) {
            Log.i(TAG, "contextObj is null");
            return;
        }
        mContentView = findContentView(contextObj);
        if (mContentView != null) {
            addContentTreeObserver();
        }
    }

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

    private void addContentTreeObserver() {
        mContentView.getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @Override
    public void onGlobalLayout() {
        int currHeight = mContentView.getHeight();//初始高度
        if (currHeight == 0) {
            Log.i(TAG, "currHeight is 0");
            return;
        }
        boolean hasChange = false;
        if (mPreHeight == 0) {
            mPreHeight = currHeight;
            mOriginHeight = currHeight;
        } else {
            if (mPreHeight != currHeight) {//說明佈局變化了,
                hasChange = true;
                mPreHeight = currHeight;
            } else {//又變化了,這裏默認回到了初始狀態
                hasChange = false;
            }
        }
        if (hasChange) {//彈出狀態
            boolean isShow;
            int keyboardHeight = 0;
            if (mOriginHeight == currHeight) {//mOriginHeight,初始高度
                //hidden
                isShow = false;
            } else {
                //show
                keyboardHeight = mOriginHeight - currHeight;//鍵盤高度
                isShow = true;
            }

            if (mKeyBoardListen != null) {
                mKeyBoardListen.onKeyboardChange(isShow, keyboardHeight);
            }
        }
    }
 /**
  * 註銷
  */
    public void destroy() {
        if (mContentView != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                mContentView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        }
    }
}

在這裏值得注意的就是巧妙的利用了一個系統佈局

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

好了 就這樣 另外給個新的Demo
如果各位小夥伴有更好的實現方法 ,分享一下哦,以前學習

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章