1. 程式人生 >實用技巧 >其它 >android監聽軟鍵盤彈出彈回事件

android監聽軟鍵盤彈出彈回事件


技術標籤:【Android】android移動開發安卓軟鍵盤

概述

針對“軟鍵盤的遮擋”問題,最簡單的方式就是將activity的windowSoftInputMode設定成adjustResize或者adjustPan。

android:windowSoftInputMode="adjustResize"
android:windowSoftInputMode="adjustPan"

其效果一般如下:

android監聽軟鍵盤彈出彈回事件

android監聽軟鍵盤彈出彈回事件

如上圖,這樣設定後能保證“當前操作的佈局”在軟鍵盤之上。
但是實際業務場景,可能需要的是“將整塊佈局”設定在軟鍵盤之上,即Demo中的兩個輸入框和按鈕都需要在軟鍵盤之上。
如果需要實現這種需求,那麼開發者就必須要監聽軟鍵盤的彈出彈回事件,然後手動來調整佈局。

監聽原始碼

監聽實現的原理如下:

  • 監聽當前頁面contentView的佈局變化
  • 如果contentView上移,那麼是軟鍵盤彈出,如果contentView底部與decorview一樣,那麼是彈回。
public class KeyBoardListenerHelper {
  //constants
  private static final String TAG = "KeyBoardListenerHelper";
  //data
  private WeakReference<Activity> weakActivity = null;//避免記憶體洩漏,使用弱引用
  private OnKeyBoardChangeListener onKeyBoardChangeListener;
  private final ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener =
      new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
          if (!isActivityValid() || onKeyBoardChangeListener == null) {
            return;
          }
          try {
            Rect rect = new Rect();
            weakActivity.get().getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
            int screenHeight = weakActivity.get().getWindow().getDecorView().getHeight();
            int keyBoardHeight = screenHeight - rect.bottom;
            onKeyBoardChangeListener.OnKeyBoardChange(keyBoardHeight > 0, keyBoardHeight);
          } catch (Exception e) {
            Log.e(TAG, "onGlobalLayout error:" + e.getMessage());
          }
        }
      };

  public KeyBoardListenerHelper(Activity activity) {
    if (activity == null) {
      return;
    }
    weakActivity = new WeakReference<>(activity);
    try {
      //設定後才可以監聽到軟鍵盤的彈出,此處不能設定SOFT_INPUT_ADJUST_UNSPECIFIED或者SOFT_INPUT_STATE_UNSPECIFIED,其他都可以.
      activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);

      View content = weakActivity.get().findViewById(android.R.id.content);
      content.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
    } catch (Exception e) {
      Log.e(TAG, "KeyBoardListenerHelper error:" + e.getMessage());
    }
  }

  //在不使用的時候需要及時銷燬,避免記憶體洩漏或造成額外開銷
  public void destroy() {
    Log.i(TAG, "destroy");
    if (!isActivityValid()) {
      return;
    }
    try {
      View content = weakActivity.get().findViewById(android.R.id.content);
      content.getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayoutListener);
    } catch (Exception e) {
      Log.e(TAG, "destroy error:" + e.getMessage());
    }
  }

  public void setOnKeyBoardChangeListener(OnKeyBoardChangeListener listener) {
    Log.i(TAG, "setOnKeyBoardChangeListener");
    this.onKeyBoardChangeListener = listener;
  }

  public interface OnKeyBoardChangeListener {

    void OnKeyBoardChange(boolean isShow, int keyBoardHeight);
  }

  public boolean isActivityValid() {
    return weakActivity != null && weakActivity.get() != null;
  }
}

監聽呼叫

呼叫步驟:

  1. 在需要的地方初始化
  2. 根據自己需要在軟鍵盤彈出和彈回的時候控制佈局變化
  3. 在不使用的及時釋放不使用的監聽器
public class MainActivity extends Activity {

  private KeyBoardListenerHelper keyBoardListenerHelper;

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

    keyBoardListenerHelper = new KeyBoardListenerHelper(this);
    keyBoardListenerHelper.setOnKeyBoardChangeListener(
        new KeyBoardListenerHelper.OnKeyBoardChangeListener() {
          @Override public void OnKeyBoardChange(boolean isShow, int keyBoardHeight) {
            //此處可以根據是否顯示軟鍵盤,以及軟鍵盤的高度處理邏輯
            Log.i("testtest", "isShow: " + isShow + " keyBoardHeight:" + keyBoardHeight);
          }
        });
  }

  @Override protected void onDestroy() {
    super.onDestroy();
    if (keyBoardListenerHelper != null) {
      keyBoardListenerHelper.destroy();//避免記憶體洩漏,需要及時釋放
    }
  }
}