2017년 5월 31일 수요일

안드로이드 Soft Keyboard 상태변화 시점 감지

안드로이드 Soft Keyboard 상태변화 감지하기

발단

안드로이드에서는 소프트키보드 상태를 변경하기 위해, 2가지 방법을 사용할 수 있을 것이다.
  • EditText에 focus를 변경하여(클릭 등) 시스템에서 자동으로 상태변화 수행
  • InputMethodManager의 showSoftInput() / hideSoftInputFromXXX() 메서드를 이용하여 명시적으로 수행
2번째 방법인 InputMethodManager를 이용한다면, 메서드의 파라미터로 ResultReceiver 를 전달하여 상태변화에 따른 콜백을 쉽게 받을수 있다. 하지만, 특별한 케이스가 아니라면 당연히 1번 방법처럼 EditText를 클릭하는 등의 방법으로 시스템이 자동으로 소프트키보드를 제어하도록 구현하는게 일반적이다. 이 때, 소프트키보드의 상태변화와 키보드의 높이를 감지하여 구현해야 할 일이 있다면....??

아이디어

구글에서 검색하던 중, 스택오버플로우에 ViewTreeObserver의 GlobalLayoutListener를 이용하는 방법을 발견했다.
http://stackoverflow.com/questions/4745988/how-do-i-detect-if-software-keyboard-is-visible-on-android-device

코드

// 파라미터로 엑티비티의 가장 최상위 layout을 받는다..
private void registerView(final View rootView) {
    if (mGlobalListener == null) {
        mGlobalListener = new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();
                // 해당 루트뷰에서 윈도우가 보이는 영역을 얻어옴
                rootView.getWindowVisibleDisplayFrame(r);

                // 루트뷰의 실제 높이와, 윈도우 영역의 높이를 비교
                // 키보드는 윈도우 영역에 위치하므로 뷰와 윈도우의 높이비교를 통해 키보드의 여부를 알 수 있다.
                int heightDiff = rootView.getRootView().getHeight() - (r.bottom - r.top);

                // keyboardThreshold는 윈도우가 기본적으로 차지하고있는 영역(StatusBar / Soft Back Button)
                int keybordHeight = heightDiff - keyboardThreshold;
                if (heightDiff > keyboardThreshold) {
                    if (!mIsKeyboardVisible) {
                        mIsKeyboardVisible = true;
                        //TODO::Keyboard invisible -> visible
                    }
                } else {
                    if (mIsKeyboardVisible) {
                        mIsKeyboardVisible = false;
                        //TODO::Keyboard visible -> invisible
                    }
                }
            }
        };
    }
    // ViewTreeObserver에 리스너 등록
    rootView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalListener);
}