본문 바로가기

Android

SearchView에서 Soft Keyboard 보여주기

SearchView가 포함되어 있는 화면에서는 화면에 진입하자마자 소프트 키보드를 보여주어 사용자에게 자연스러운 입력을 유도할 수 있다.

그렇기 때문에 SearchView나 EditText를 가진 화면에서 소프트키보드가 팝업되는 것은 중요한 요소이다.

SearchView가 Focusable하게 만들기

우선 SearchView에서 소프트 키보드를 보여주기 위해서는 해당 뷰에 Focus를 지녀야한다.

우선 xml에서 focusable을 지정하거나 클래스 내에서 매뉴얼하게 지정해준다.

    searchView.setFocusable(true)

SearchView에 Focus가 이동한 것을 감지하는 리스너 등록하기

그 다음은 SearchView에 focus가 되었을 때를 인지하는 리스너를 등록해야한다.

    searchView.setOnQueryTextFocusChangeListener { searchView, hasFocus ->  
            if (hasFocus) {
                // focus 를 가지고 있는 경우
            }
        }

여기서 주의할 점은 setOnFocusChangeListener가 아니라 setOnQueryTextFocusChangeListener 에 등록해야한다.

Listener에서 SoftKeyboard 팝업하기

    searchView.setOnQueryTextFocusChangeListener { searchView, hasFocus ->  
            if (hasFocus) {
                // focus 를 가지고 있는 경우 - show keyboard
                val imm: InputMethodManager = getContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, InputMethodManager.HIDE_IMPLICIT_ONLY)
            }
        }

토글 소프트 키보드를 이용해서 소프트 키보드를 불러온다.

화면을 벗어날 때 소프트 키보드 숨기기

이렇게 키보드를 보여주고 난 뒤에 화면이 벗어나도 소프트 키보드가 자동으로 사라지지 않을 수 있다.
위에서 SHOW_IMPLICIT 플래그를 통해서 키보드를 보여줬기 때문에, searchView에서 포커스가 벗어나면 키보드는 사라지게 된다.

 

그래서 입력이 필요한 상황이 끝나면, 뷰에서 포커스를 제거하여 키보드가 사라질 수 있도록 한다.

    searchView.clearFocus()

toggleSoftInput() will be deprecated in API 31

새롭게 나온 androidx.core:core-splashscreen 을 적용하기 위해서 프로젝트의 compiledSdkVersion을 31로 변경했다.

 

그리고 나서 보니 toggleSoftInput() 기능이 해당 API부터 deprecated 된다는걸 확인할 수 있었다.

 

그래서 toggle 대신에 showSoftInput() 메소드를 사용하도록 수정해보도록 한다.

showSoftInput() 이 동작하지 않았던 이유

하지만 처음 showSoftInput() 을 사용해서 키보드를 보여주려고 했지만 키보드가 전혀 보여지지 않았다.

여러가지 플래그를 바꿔도 전혀 키보드가 보여지지 않아서 이리저리 로그를 찍어본 결과

    searchView.isFocusable              // true
    searchView.requestFocus()        // 뷰에 focus를 가지도록 명령
    searchView.isFocused                // false

    val isShowed = imm.showSoftInput(searchView, InputMethodManager.SHOW_IMPLICIT)

    // 결과 : isShowed : false

인 상태를 확인하였다.

 

1. 서치뷰는 포커스를 가질 수 있는 상태이고,

2. 포커스를 가지도록 명령을 내렸지만,
3. 포커스를 가지지 못하는 중임을 발견했다.

 

그래서 showSoftInput의 파라미터로 전달된 searchView가 포커스를 가진 상태가 아니기 때문에 키보드가 팝업하지 않는 상황이었다..

해결책

실제 Focused 된 뷰를 찾아본다.

searchView.findFocus() 를 출력해본 결과...
포커스를 가진 뷰가 searchView가 아닌 다른 뷰를 반환하는 것을 확인했다.

 

그래서 SearchView 클래스를 찾아보니..

실제 포커스를 가지고 있는 뷰는 SearchView 본인이 아니라, SearchView 내에 위치한 SearchAutoComplete 이라는 확장된 TextView 라는 것을 확인할 수 있었다.

 

그럼 포커스를 가지고 있는 뷰를 showSoftInput() 메소드에 전달해주면 키보드가 잘 보여질 것이다.

    val popUpSoftKeyboard =  View.OnFocusChangeListener { view, hasFocus ->
        val imm : InputMethodManager = getContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager

        if (hasFocus) {
            val isShowed = imm.showSoftInput(view.findFocus(), InputMethodManager.SHOW_IMPLICIT)
            Logger.d(" ## hasFocus -> $hasFocus , isShowing -> $isShowed")        // both are true!
        }
    }


    setOnQueryTextFocusChangeListener(popUpSoftKeyboard)        // 리스너 등록

showSoftInput 메소드에 searchView가 아니라 searchView.findFocus()를 전달해줘야한다.