본문 바로가기
Mobile App/Android

[안드로이드] 키보드 자판이 보이고 안 보이고 감지하는 콜백함수 (Keyboard show hide)

by Jman 2024. 1. 28.

문제 정의

현재 회사 코드 정책 상, 싱글 액티비티를 유지해야 했고, Fragment 에 원하는 softInputMode 를 적용하고 싶었다.

그리고 AndroidManifest.xml 내에 windowSoftInputMode 가 세팅이 되어있지 않았다.

즉, default 모드 상태인 stateUnspectified 값이며 이 속성은 시스템에서 적절한 상태를 선택하거나 테마의 설정을 사용하게 한다.

 

 

그러다보니 Fragment UI 작업 시, 하단 버튼이 editText 에 focusing 이 될 때마다 올라오게 되며 원치않게 버튼이 뷰를 가리게 됐다.

매니페스트에 내가 원하는 속성을 적용하게 될 경우, 앱 내 여러 서비스들 중에 EditText 를 사용하는 부분에 영향이 가서 고민하게 됐다.

 

 

일단, AndroidManifest.xml 에 아래와 같이 설정을 하게 될 경우,

다른 서비스 소스코드에 추가 작업이 필요하게 된다.

내가 원하는 adJustPan 으로 매니페스트에 초기 세팅을 하게된다면? 다른 서비스를 하나하나 확인하면서 키보드에 영향을 받아 UI 가 오작동하는 걸 확인하면서 해당 서비스 소스코드 onCreate(), onDestroy() 함수에서 softInputMode 를 변경을 해주어야 한다.
(ref. https://xabaras.medium.com/setting-windowsoftinputmode-for-a-single-fragment-c0b386463986)

<activity android:windowSoftInputMode="adjustPan" />

 

그래서 아래와 같은 방법을 시도 해봤지만 되지 않았다.

싱글 액티비티 내에 코드로 소프트 키보드 제어 default(unspectified) 속성을 세팅 후, fragment 내 onCreate 에서 softInputMode 를 변경 후, fragment 가 destroy 됐을 때, 기존에 사용한 softInputMode 로 원복시키기 (실패)

 

그래서 생각한 건, 키보드가 올라 갔을 경우, 버튼을 View.Gone 하고, 키보드가 내려갈 경우, View.Visible 처리를 할 수 있게 키보드 자판이 show, hide 하는 콜백함수를 만들게 됐다.

 

1. 인터페이스 생성

interface KeyboardStateChangeListener {
    fun change(isVisible: Boolean)
}

 

2. FragmentActivity 확장함수 

fun FragmentActivity.setKeyboardStateChangeListener(listener: KeyboardStateChangeListener) {
    val view = window.decorView
    view.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
        var mIsVisible: Boolean = view.isVisibleKeyboard()
        override fun onGlobalLayout() {
            val windowInsetsCompat = ViewCompat.getRootWindowInsets(view)

            // 키보드 상태가 변했을때
            val isVisible = windowInsetsCompat?.isVisible(WindowInsetsCompat.Type.ime()) ?: view.isVisibleKeyboard()
            (isVisible != mIsVisible).isTrue {
                listener.change(isVisible)
            }
            mIsVisible = isVisible
        }
    })
}

 

키보드 속성을 변경하기 위해선 Activity 에서 작업을 해야해서 확장함수를 하나 만들었다.

 

3. 리스너 등록

requireActivity().setKeyboardStateChangeListener(object : KeyboardStateChangeListener {
    override fun change(isVisible: Boolean) {
        if (isVisible) {
            binding.btnSmsRequest.visibility = View.GONE
        } else {
            binding.btnSmsRequest.visibility = View.VISIBLE
        }
    }
})

 

이렇게 내가 원하는 Fragment 에 위와 같이 리스너 등록을 해주어 키보드에 따른 UI 작업을 내가 원하게끔 할 수 있다.