입력 포커스가 수정 가능한 텍스트 필드 안이나 밖으로 이동하면 Android에서는 필요에 따라 입력(예: 터치 키보드)을 표시하거나 숨깁니다. 시스템은 UI와 텍스트 필드가 입력 방법 위에 표시되는 방법도 결정합니다. 예를 들어 화면의 세로 공간이 제한되면 텍스트 필드가 입력 방법 위의 모든 공간을 채울 수 있습니다.
대부분의 앱에 이러한 기본 동작만 있으면 됩니다. 하지만 입력 방법의 가시성과 레이아웃이 레이아웃에 미치는 영향을 더 세밀하게 제어해야 하는 경우도 있습니다. 이 과정에서는 입력 방법의 가시성을 제어하고 응답하는 방법을 설명합니다.
활동이 시작될 때 소프트 키보드를 표시합니다.
Android는 활동이 시작될 때 레이아웃의 첫 번째 텍스트 필드에 포커스를 두지만 소프트 키보드는 표시하지 않습니다. 텍스트 입력이 활동의 기본 작업이 아닐 수 있으므로 이 동작은 적절합니다. 그러나 텍스트 입력이 실제로 주요 작업(예: 로그인 화면)인 경우 소프트 키보드를 기본적으로 표시하는 것이 좋습니다.
활동이 시작될 때 입력 방법을 표시하려면 "stateVisible"
값을 사용하여 android:windowSoftInputMode
속성을 <activity>
요소에 추가합니다. 예:
<application ... >
<activity
android:windowSoftInputMode="stateVisible" ... >
...
</activity>
...
</application>
UI 응답 방식 지정
소프트 키보드가 화면에 표시되면 앱의 UI에 사용할 수 있는 공간이 줄어듭니다. UI에 표시되는 부분을 조정하는 방법은 시스템이 결정하지만 제대로 하지 못할 수도 있습니다. 앱이 가장 잘 동작하게 하려면 시스템에서 나머지 공간에 UI를 표시하는 방법을 지정합니다.
원하는 활동 처리를 선언하려면 매니페스트의 <activity>
요소에서 android:windowSoftInputMode
속성을 'adjust' 값 중 하나와 함께 사용합니다.
예를 들어 시스템에서 레이아웃 크기를 사용 가능한 공간에 맞춰 조정하도록 하려면(스크롤이 필요하더라도 모든 레이아웃 콘텐츠에 액세스할 수 있도록 함) 다음과 같이 "adjustResize"
를 사용합니다.
<application ... >
<activity
android:windowSoftInputMode="adjustResize" ... >
...
</activity>
...
</application>
조정 사양과 이전 섹션의 초기 소프트 키보드 공개 상태 사양과 결합할 수 있습니다.
<activity
android:windowSoftInputMode="stateVisible|adjustResize" ... >
...
</activity>
UI에 사용자가 텍스트를 입력한 직후나 입력하는 동안 액세스해야 할 수도 있는 컨트롤이 포함된 경우 "adjustResize"
를 지정하는 것이 중요합니다. 예를 들어 상대적 레이아웃을 사용하여 화면 하단에 버튼 모음을 배치하는 경우 "adjustResize"
를 사용하면 레이아웃의 크기가 조절되어 버튼 모음이 소프트 키보드 위에 표시됩니다.
요청 시 소프트 키보드 표시
활동의 수명 주기에 입력 방법을 표시해야 하는 메서드가 있는 경우 InputMethodManager
를 사용하여 표시하면 됩니다.
예를 들어 다음 메서드는 사용자가 무언가를 입력할 것으로 예상되는 View
를 사용하고 requestFocus()
를 호출하여 포커스를 부여한 다음 showSoftInput()
를 호출하여 입력 방법을 엽니다.
Kotlin
fun showSoftKeyboard(view: View) { if (view.requestFocus()) { val imm = getSystemService(InputMethodManager::class.java) imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT) } }
Java
public void showSoftKeyboard(View view) { if (view.requestFocus()) { InputMethodManager imm = getSystemService(InputMethodManager.class); imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT); } }
소프트 키보드를 안정적으로 표시
활동이 시작될 때와 같이 InputMethodManager.showSoftInput()
를 사용하여 소프트 키보드를 표시하면 소프트웨어 키보드가 사용자에게 표시되지 않는 특정 상황이 있습니다.
showSoftInput()
사용 시 소프트 키보드의 표시 여부는 다음 조건에 따라 달라집니다.
보기가 이미 소프트웨어 키보드에 연결되어 있어야 합니다. 따라서 창에 포커스가 지정되고 편집기 뷰에서
View.requestFocus()
를 사용하여 뷰 포커스를 요청해야 합니다.공개 상태는
android:windowSoftInputMode
속성과showSoftInput()
에서 사용하는 플래그의 영향을 받을 수도 있습니다.
활동이 시작될 때와 같은 특정 사용 사례에서는 이러한 필수 조건 중 일부가 충족되지 않습니다. 시스템은 뷰를 소프트웨어 키보드에 연결된 것으로 간주하지 않고, showSoftInput()
호출을 무시하며, 소프트 키보드가 사용자에게 표시되지 않습니다.
소프트웨어 키보드를 안정적으로 표시하려면 다음 대안을 사용할 수 있습니다.
- (권장)
WindowInsetsControllerCompat
을 사용합니다. 이 객체는 다음 코드 스니펫에서와 같이Activity.onCreate()
중에 소프트 키보드를 표시합니다. 호출은 창에 포커스가 맞춰진 후에 예약됩니다.
Kotlin
editText.requestFocus() WindowCompat.getInsetsController(window, editText)!!.show(WindowInsetsCompat.Type.ime())
Java
editText.requestFocus(); WindowCompat.getInsetsController(getWindow(), editText).show(WindowInsetsCompat.Type.ime());
- 실행 가능 항목을 게시합니다. 이렇게 하면 앱이
showSoftInput()
를 호출하기 전에View.onWindowFocusChanged()
에서 창 포커스 이벤트를 수신할 때까지 대기합니다.
Kotlin
class MyEditText : EditText() { ... override fun onWindowFocusChanged(hasWindowFocus: Boolean) { if (hasWindowFocus) { requestFocus() post { val imm: InputMethodManager = getSystemService(InputMethodManager::class.java) imm.showSoftInput(this, 0) } } } }
Java
public class MyEditText extends EditText { ... @Override public void onWindowFocusChanged(boolean hasWindowFocus) { if (hasWindowFocus) { requestFocus(); post(() -> { InputMethodManager imm = getSystemService(InputMethodManager.class); imm.showSoftInput(this, 0); }); } } }
런타임 공개 상태 플래그를 신중하게 처리
런타임 시 소프트 키보드 공개 상태를 전환할 때 특정 플래그 값을 이러한 메서드에 전달하지 않도록 주의하세요. 예를 들어 활동이 시작되는 동안 Activity.onCreate()
에서 View.getWindowInsetsController().show(ime())
를 호출할 때 애플리케이션에서 소프트 키보드가 표시된다고 예상하는 경우 애플리케이션 개발자는 소프트 키보드가 예기치 않게 숨겨지는 경우 초기 실행 중에 SOFT_INPUT_STATE_HIDDEN
또는 SOFT_INPUT_STATE_ALWAYS_HIDDEN
플래그를 설정하지 않도록 주의해야 합니다.
시스템에서 일반적으로 소프트 키보드를 자동으로 숨김
대부분의 경우 시스템에서 소프트 키보드를 숨기는 작업을 처리합니다. 이는 다음 중 하나일 수 있습니다.
- 사용자가 텍스트 필드에서 작업을 완료합니다.
- 사용자가 뒤로 탐색으로 뒤로 키 또는 스와이프 동작을 누릅니다.
- 사용자가 다른 앱으로 이동하고 뷰가 포커스를 받을 때 다른 앱은
SOFT_INPUT_STATE_HIDDEN
또는SOFT_INPUT_STATE_ALWAYS_HIDDEN
플래그를 설정했습니다.
이전 시스템 동작에 따라 수동으로 소프트 키보드를 숨깁니다.
앱은 일부 상황(예: View.OnFocusChangeListener.onFocusChange
에서 텍스트 필드의 포커스를 잃는 경우)에서 수동으로 소프트 키보드를 숨겨야 합니다. 이 기법을 현명하게 사용하세요. 소프트 키보드를 닫으면 예기치 않게 사용자 환경이 저하됩니다.
앱에서 소프트 키보드를 수동으로 숨기는 경우 소프트 키보드가 명시적으로 표시되었는지 암시적으로 표시되었는지 알아야 합니다.
소프트 키보드는
showSoftInput()
호출 후 명시적으로 표시된 것으로 간주됩니다.반대로 소프트 키보드는 다음 조건 중 하나에서 암시적으로 표시된 것으로 간주됩니다.
- 시스템은
android:windowSoftInputMode
를 적용하는 동안 소프트 키보드를 표시했습니다. - 앱이
SHOW_IMPLICIT
를showSoftInput()
에 전달했습니다.
- 시스템은
일반적으로 hideSoftInputFromWindow()
는 요청 방법에 관계없이 소프트 키보드를 숨기지만 HIDE_IMPLICIT_ONLY
를 사용하면 암시적으로 요청된 소프트 키보드를 닫기만 하도록 제한할 수 있습니다.
소프트 키보드 위에 대화상자 또는 오버레이 뷰 표시
경우에 따라 편집기 활동이 소프트 키보드 위에 수정 불가능한 대화상자나 오버레이 창을 만들어야 할 수도 있습니다.
앱에는 다음 섹션에서 설명하는 몇 가지 옵션이 있습니다.
요약하면, 세로 (z-레이어) 순서 지정과 관련된 다음 기대치를 충족하도록 창을 타겟팅하는 소프트 키보드의 창 플래그를 올바르게 처리해야 합니다.
- 플래그 없음 (일반 사례): 소프트 키보드 레이어 뒤에 텍스트를 수신할 수 있습니다.
FLAG_NOT_FOCUSABLE
: 소프트 키보드 레이어 위에 위치하지만 텍스트를 수신할 수 없습니다.FLAG_ALT_FOCUSABLE_IM
: 소프트 키보드 레이어 위에 있으며 포커스가 있을 수 있지만 소프트 키보드에 연결되지 않습니다. 또한 그 아래에 있는 모든 뷰가 소프트 키보드에 연결되지 않도록 차단합니다. 이는 소프트 키보드 레이어 위에서 텍스트 입력을 사용하지 않는 앱 대화상자를 표시하는 데 유용합니다.FLAG_NOT_FOCUSABLE
및FLAG_ALT_FOCUSABLE_IM
: 소프트 키보드 레이어 뒤에 있지만 텍스트를 수신할 수 없습니다.FLAG_NOT_FOCUSABLE
및FLAG_NOT_TOUCH_MODAL
: 소프트 키보드 위에 있으며 터치 이벤트가 창을 '통해' 소프트 키보드로 이동할 수 있도록 합니다.
대화상자 만들기
대화상자를 소프트 키보드 상단에 유지하고 소프트 키보드가 포커스를 얻지 못하도록 하려면 FLAG_ALT_FOCUSABLE_IM
대화상자 창 플래그를 사용합니다.
Kotlin
val content = TextView(this) content.text = "Non-editable dialog on top of soft keyboard" content.gravity = Gravity.CENTER val builder = AlertDialog.Builder(this) .setTitle("Soft keyboard layering demo") .setView(content) mDialog = builder.create() mDialog!!.window!! .addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) mDialog!!.show()
Java
TextView content = new TextView(this); content.setText("Non-editable dialog on top of soft keyboard"); content.setGravity(Gravity.CENTER); final AlertDialog.Builder builder = new AlertDialog.Builder(this) .setTitle("Soft keyboard layering demo") .setView(content); mDialog = builder.create(); mDialog.getWindow().addFlags(FLAG_ALT_FOCUSABLE_IM); mDialog.show();
오버레이 뷰 만들기
소프트 키보드 타겟팅 활동으로 TYPE_APPLICATION_OVERLAY
창 유형 및 FLAG_ALT_FOCUSABLE_IM
창 플래그를 지정하는 오버레이 뷰를 만듭니다.
Kotlin
val params = WindowManager.LayoutParams( width, /* Overlay window width */ height, /* Overlay window height */ WindowManager.LayoutParams.TYPE_APPLICATION, /* Overlay window type */ WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM /* No need to allow for text input on top of the soft keyboard */ or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, /* Allow touch event send to soft keyboard behind the overlay */ PixelFormat.TRANSLUCENT ) params.title = "Overlay window" mOverlayView!!.layoutParams = params windowManager.addView(mOverlayView, params)
Java
WindowManager.LayoutParams params = new WindowManager.LayoutParams( width, /* Overlay window width */ height, /* Overlay window height */ TYPE_APPLICATION, /* Overlay window type */ FLAG_ALT_FOCUSABLE_IM /* No need to allow for text input on top of the soft keyboard */ | FLAG_NOT_TOUCH_MODAL, /* Allow touch event send to soft keyboard behind the overlay */ PixelFormat.TRANSLUCENT); params.setTitle("Overlay window"); mOverlayView.setLayoutParams(params); getWindowManager().addView(mOverlayView, params);
소프트 키보드 아래에 대화상자 또는 뷰 표시
앱은 다음과 같은 속성이 있는 대화상자나 창을 만들어야 할 수도 있습니다.
- 텍스트 입력의 영향을 받지 않도록 편집기 활동에서 요청한 소프트 키보드 아래에 표시됩니다.
- 대화상자나 창의 레이아웃을 조정하기 위해 소프트 키보드의 인셋 크기 변경사항을 인지해야 합니다.
이 경우 앱에는 몇 가지 옵션이 있습니다. 다음 섹션에서는 이러한 옵션을 설명합니다.
대화상자 만들기
FLAG_NOT_FOCUSABLE
창 플래그와 FLAG_ALT_FOCUSABLE_IM
창 플래그를 모두 설정하여 대화상자를 만듭니다.
Kotlin
val content = TextView(this) content.text = "Non-editable dialog behind soft keyboard" content.gravity = Gravity.CENTER val builder = AlertDialog.Builder(this) .setTitle("Soft keyboard layering demo") .setView(content) mDialog = builder.create() mDialog!!.window!! .addFlags(FLAG_NOT_FOCUSABLE or FLAG_ALT_FOCUSABLE_IM) mDialog!!.show()
Java
TextView content = new TextView(this); content.setText("Non-editable dialog behind soft keyboard"); content.setGravity(Gravity.CENTER); final AlertDialog.Builder builder = new AlertDialog.Builder(this) .setTitle("Soft keyboard layering demo") .setView(content); mDialog = builder.create(); mDialog.getWindow() .addFlags(FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM); mDialog.show();
오버레이 뷰 만들기
FLAG_NOT_FOCUSABLE
창 플래그와 FLAG_ALT_FOCUSABLE_IM
창 플래그를 모두 설정하여 오버레이 뷰를 만듭니다.
Kotlin
val params = WindowManager.LayoutParams( width, /* Overlay window width */ height, /* Overlay window height */ WindowManager.LayoutParams.TYPE_APPLICATION, /* Overlay window type */ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, PixelFormat.TRANSLUCENT ) params.title = "Overlay window" mOverlayView!!.layoutParams = params windowManager.addView(mOverlayView, params)
Java
WindowManager.LayoutParams params = new WindowManager.LayoutParams( width, /* Overlay window width */ height, /* Overlay window height */ TYPE_APPLICATION, /* Overlay window type */ FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM, PixelFormat.TRANSLUCENT); params.setTitle("Overlay window"); mOverlayView.setLayoutParams(params); getWindowManager().addView(mOverlayView, params);