안드로이드 키보드 상태 확인 - andeuloideu kibodeu sangtae hwag-in

1. 존재 여부 확인

Show

context.getResources().getConfiguration().keyboard

Configuration.KEYBOARD_NOKEYS : 없음

Configuration.KEYBOARD_QWERTY : qwerty keyboard 있음

Configuration.KEYBOARD_12KEY : 12key keyboard 있음

2. 사용 여부 확인 (h/w keyboard가 열려 있나?)

context.getResources().getConfiguration().hardKeyboardHidden

Configuration.HARDKEYBOARDHIDDEN_NO : 사용상태(열려 있음)

Configuration.HARDKEYBOARDHIDDEN_YES : 사용하지 않는 상태(닫혀 있음)

키보드를 올렸을 때 안에 있는 레이아웃이 전체적으로 움직이거나 고정시키고 싶을 때가 있습니다.

이번 포스팅에서는 키보드의 영향에 따라 레이아웃을 조정하는 코드를 작성해보겠습니다.

우선 키보드 화면조정의 속성에는 다음과 같습니다.

  • Default(설정이 안 된 경우) : ajdustUnspecified와 stateUnspecified 적용됩니다.
  • adjustPan : 키보드가 올라올 때  UI화면도 같이 위로 올라갑니다.
  • adjustResize : 키보드가 올라갈 때 액티비티의 크기를 조정해줍니다.
  • adjustUnspecified : 시스템이 알아서 상황에 맞는 옵션을 설정해줍니다.
  • stateHidden : 액티비티를 실행했을 때 키보드가 자동으로 올라오는것을 방지합니다.
  • stateVisible : 액티비티를 실행하면 키보드가 자동으로 올라옵니다.
  • stateUnspecified : 시스템이 적절한 키보드 상태를 설정해줍니다.
안드로이드 키보드 상태 확인 - andeuloideu kibodeu sangtae hwag-in

위는 adjustPan을 적용한 것으로, 키보드가 올라갈 때 UI화면도 같이 올라가게 되는것을 확인할 수 있습니다.

manifests.xml

<activity android:name=".MainActivity"
            android:windowSoftInputMode="adjustPan">
안드로이드 키보드 상태 확인 - andeuloideu kibodeu sangtae hwag-in

위는 adjustResize로 키보드가 올라갈 때 액티비티는 고정되어있습니다. 하지만 너무 고정되어있는 탓에 입력할 수 있는 EditText가 보이지 않아 문제가 있습니다. 

manifest.xml

<activity android:name=".MainActivity"
            android:windowSoftInputMode="adjustResize">

이 문제를 해결하기 위해서는 xml코드에서 레이아웃을 바꿔줘야합니다.

안드로이드 키보드 상태 확인 - andeuloideu kibodeu sangtae hwag-in

저는 최상위 레이아웃을 RelativeLayout로 만들어 준 뒤, EditText를 바닥에 붙여주니 다음과 같이 키보드 위에 EditText가 붙는 것을 확인할 수 있습니다.


SampleCode

RelativeLayout의 구성은 다은과 같습니다.

activity_main.xml

	
    <?xml version="1.0" encoding="utf-8"?>
	<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
	    xmlns:app="http://schemas.android.com/apk/res-auto"
	    xmlns:tools="http://schemas.android.com/tools"
	    android:layout_width="match_parent"
	    android:layout_height="match_parent"
	    tools:context=".MainActivity">
	
	    <LinearLayout
	        android:orientation="vertical"
	        android:layout_width="match_parent"
	        android:layout_height="wrap_content">
	
	        <Button
	            android:layout_marginTop="5dp"
	            android:id="@+id/btn_hide_keyboard"
	            android:text="키보드 숨기기"
	            android:layout_width="match_parent"
	            android:layout_height="wrap_content"/>
	
	        <Button
	            android:layout_marginTop="5dp"
	            android:id="@+id/btn_show_keyboard"
	            android:text="키보드 보이기"
	            android:layout_width="match_parent"
	            android:layout_height="wrap_content"/>
	
	        <View
	            android:layout_marginTop="5dp"
	            android:background="#AB98DC"
	            android:layout_width="match_parent"
	            android:layout_height="200dp"/>
	
	        <View
	            android:layout_marginTop="5dp"
	            android:background="#E4D972"
	            android:layout_width="match_parent"
	            android:layout_height="200dp"/>
	
	        <View
	            android:layout_marginTop="5dp"
	            android:background="#2A7495"
	            android:layout_width="match_parent"
	            android:layout_height="150dp"/>
	    </LinearLayout>
	
	
	    <EditText
	        android:id="@+id/editText"
	        android:layout_width="match_parent"
	        android:layout_height="wrap_content"
	        android:layout_alignParentBottom="true"
	        app:layout_constraintBottom_toBottomOf="parent" />
	</RelativeLayout>
	

EditText만 바닥에 붙여주기만 하면 키보드 위에 붙도록 구현할 수 있습니다.

발단

안드로이드에서는 소프트키보드 상태를 변경하기 위해, 2가지 방법을 사용할 수 있을 것이다.

  • EditText에 focus를 변경하여(클릭 등) 시스템에서 자동으로 상태변화 수행
  • InputMethodManager의 showSoftInput() / hideSoftInputFromXXX() 메서드를 이용하여 명시적으로 수행

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

아이디어

코드

// 파라미터로 엑티비티의 가장 최상위 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);
}