문제 정의
현재 회사 코드 정책 상, 싱글 액티비티를 유지해야 했고, 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 작업을 내가 원하게끔 할 수 있다.