Android에서는 소프트 키보드의 열림과 닫힘 상태를 직접 알려주는 공식 API가 없기 때문에, 뷰의 레이아웃 변화를 관찰하는 방식으로 키보드 표시 여부를 감지해야 합니다. 이 예제에서는 ViewTreeObserver.OnGlobalLayoutListener를 활용해 액티비티에서 소프트 키보드가 열리고 닫히는 이벤트를 감지하는 리스너를 구현하는 방법을 단계별로 살펴보겠습니다.
동작 원리
핵심 아이디어는 간단합니다. 화면 전체 높이에서 현재 실제로 보이는 영역(getWindowVisibleDisplayFrame)의 높이를 빼면 키보드가 차지하는 높이를 계산할 수 있습니다. 이 값이 화면 높이의 일정 비율(예: 15%)보다 크면 키보드가 열린 것으로 판단하고, 그렇지 않으면 닫힌 것으로 판단합니다.
구현 단계
1단계 — 새 프로젝트 생성
Android Studio에서 File ⇒ New Project로 이동한 후, 새 프로젝트 생성에 필요한 모든 세부 정보를 입력하여 프로젝트를 만듭니다.
2단계 — 레이아웃 파일 작성
res/layout/activity_main.xml에 다음 코드를 추가합니다. 루트 뷰에 id를 지정하고, EditText와 버튼 하나를 배치합니다.
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android" xmlns:app="https://schemas.android.com/apk/res-auto" xmlns:tools="https://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:id = "@+id/rootView" tools:context=".MainActivity"> <EditText android:id = "@+id/editText" android:layout_width = "match_parent" android:layout_height = "wrap_content" tools:ignore="MissingConstraints"> </EditText> <Button android:id = "@+id/btnButton" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "Click here to hide" app:layout_constraintBottom_toBottomOf = "parent" app:layout_constraintLeft_toLeftOf = "parent" app:layout_constraintRight_toRightOf = "parent" app:layout_constraintTop_toTopOf = "parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
3단계 — MainActivity 작성
src/MainActivity.java에 다음 코드를 추가합니다. onCreate()에서 루트 뷰의 ViewTreeObserver에 OnGlobalLayoutListener를 등록하고, onGlobalLayout() 콜백 안에서 키보드 높이를 계산해 상태를 판별합니다.
package com.app.sample;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;
import android.os.Bundle;
import android.graphics.Rect;
import android.os.Build;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
ConstraintLayout constraintLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.btnButton);
EditText editText=findViewById(R.id.editText);
editText.requestFocus();
constraintLayout=findViewById(R.id.rootView);
constraintLayout.getViewTreeObserver().addOnGlobalLayoutListener(new
ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
constraintLayout.getWindowVisibleDisplayFrame(r);
int screenHeight = constraintLayout.getRootView().getHeight();
int keypadHeight = screenHeight - r.bottom;
if (keypadHeight > screenHeight * 0.15) {
Toast.makeText(MainActivity.this,"Keyboard is showing",Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this,"keyboard closed",Toast.LENGTH_LONG).show();
}
}
});
button.setOnClickListener(this);
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnButton:
hideSoftkeybard(v);
break;
}
}
private void hideSoftkeybard(View v) {
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}코드의 주요 부분을 살펴보면 다음과 같습니다.
- editText.requestFocus() — 앱 실행 시 EditText에 포커스를 두어 키보드가 자동으로 나타나도록 합니다.
- addOnGlobalLayoutListener() — 뷰 계층 구조의 레이아웃이 변경될 때마다 호출되는 리스너를 등록합니다. 키보드가 열리거나 닫히면 화면 배치가 달라지므로 이 콜백이 트리거됩니다.
- keypadHeight > screenHeight * 0.15 — 키보드가 차지하는 높이가 화면 전체의 15%를 초과하면 '키보드 표시 중'으로 판단합니다. 이 임계값은 기기나 상황에 맞게 조절할 수 있습니다.
- hideSoftInputFromWindow() — 버튼 클릭 시 InputMethodManager를 통해 키보드를 강제로 숨깁니다.
4단계 — 매니페스트 설정
Manifests/AndroidManifest.xml에 다음 코드를 추가합니다.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="https://schemas.android.com/apk/res/android" package="com.app.sample"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
앱 실행 및 결과 확인
이제 애플리케이션을 실행해 보겠습니다. 실제 Android 모바일 기기를 컴퓨터에 연결했다고 가정합니다. Android Studio에서 프로젝트의 액티비티 파일 중 하나를 연 뒤 툴바의 Run 아이콘을 클릭하세요. 실행 옵션에서 본인의 모바일 기기를 선택하면, 기기 화면에 아래와 같은 결과가 표시됩니다.

EditText를 탭하면 키보드가 올라오면서 "Keyboard is showing"(키보드 표시 중) 토스트 메시지가 나타나고, 버튼을 누르거나 뒤로 가기로 키보드를 내리면 "keyboard closed"(키보드 닫힘) 메시지가 표시되는 것을 확인할 수 있습니다.