Android 개발을 진행하다보면 Keyboard Height 를 알고싶은 상황을 마주할 때가 있다. 하지만 안타깝게도 Android에서 Keyboard Height 를 알 수 있는 native API 는 제공되지 않는다. 따라서 약간의 편법(?)을 통해 값을 알아내야 하는데, 오늘 포스팅에서는 그 과정을 다뤄보려 한다. Show 원리Keyboard height 를 구하는 방법에 대한 다양한 접근법이 제시되고 있으나, 결국 핵심원리는 다음과 같다.
구현화면이라는 단어는 자체는 매우 추상적이다. 위 원리의 핵심은 화면의 높이를 구하는 것이므로 코드 레벨의 사전 정의가 필요해보인다. 해당 포스트에서는 안드로이드에서 제공하고 있는 View 클래스를 화면으로 정의했다. 그 이유는 높이를 구하는 과정에서 활용할 수 있는 API 가 모두 View 에서 제공되기 때문이다. 1. 화면의 높이를 구한다.View 는 getHeight() 메소드를 제공하기 때문에, 높이를 알아는 것이 어렵지 않다. 문제는 getHeight() 를 통해 얻어온 높이가 해당 View 의 정확한 높이라고 보장할 수 없다. 왜냐하면 View 의 높이는 초기화되자마자 결정되는 것이 아니라 일련의 측정 단계를 거쳐 결정이 되는데, 그 단계가 끝나기 전에 getHeight() 를 호출했을수도 있기 때문이다. 따라서 정확한 View 의 높이를 알기 위해서는 View 의 크기가 결정된 이후에 getHeight() 를 호출해야 한다. View 에서 제공하는 ViewTreeObserver.OnGlobalLayoutListener 를 이용하면 결정되는 타이밍을 캐치할 수 있다. OnGlobalLayoutListener 는 해당 View에 변경점이 생겼을 때, 이를 콜백형태로 감지할 수 있다. 변경되는 내용에는 View 의 크기가 결정되는 것도 포함되므로 우리는 해당 콜백이 호출되었을 때 View.getHeight() 를 호출하면 정확한 높이를 얻을 수 있다. 코드 레벨로는 다음과 같다.
2. Keyboard 가 올라왔을 때, Keyboard 가 가리고 있는 부분을 제외한 화면의 높이를 구한다.이 과정은 두가지 단계로 나누어 생각해보자.
(1) Keyboard 가 언제 올라왔는지 감지1단계는 다시 ViewTreeObserver.OnGlobalLayoutListener 를 이용하여 진행할 수 있다. Keyboard 의 활성화/비활성화를 감지하는 아이디어는 다음과 같다.
View 를 이용할 수 있는 것은 알았다. 그럼 우리는 어떤 View 를 이용하여 위 과정을 진행해야할까? 1) Activity 의 RootLayout 을 이용한다.가장 무난하고 쉬운 선택이다. Acitivity 의 Xml 에서 root level 에 있는 layout 을 View 로 이용하는 방법이다. 실제로도 대부분의 케이스에서는 잘 동작한다. 하지만 이 방법은 치명적인 단점이 존재한다. Activity 의 windowSoftInputMode 옵션 값에따라 정상적으로 동작하지 않을 수 있다는 것이다. windowSoftInputMode 옵션은 가상 Keyboard 와 Activity 의 상호작용을 지정하는 옵션인데, ‘AdjustNothing’ 와 같은 일부 옵션값은 Keyboard 가 올라와도 Activity Height 의 변화가 없기 때문에 두번째 단계를 수행할 수 없다. 따라서 Acitivity 의 windowSoftInputMode 값에 따라 동일한 결과를 보장받지 못하기 때문에, 범용적으로 활용되기 어렵다. 좀 더 개선된 선택지이다. PopupWindow 는 고유의 SoftInputMode 을 별도로 지정할 수 있다. 따라서 Acitivity windowSoftInputMode 옵션이 무엇이든 영향을 받지 않고, 독립적으로 활용이 가능하다. 따라서 RootLayout 을 이용하는 1번 방식의 단점을 보완할 수 있다.
(2) 현재 화면상에 보여지고 있는 영역의 높이 구하기2단계는 View 에서 제공하는 View.getWindowVisibleDisplayFrame() 를 활용하여 진행할 수 있다. getWindowVisibleDisplayFrame(rect) 메소드는 해당 View 를 그리고 있는 window 를 기준으로, 현재 보여지고 있는 영역의 크기를 반환한다. 따라서, Keyboard가 올라왔을 때 해당 메소드를 호출할 경우 Keyboard로 인하여 가려진 영역을 제외한 화면의 높이를 얻을 수 있다.
3. Keyboard 의 높이 구하기각 과정의 결과를 빼기면 하면 Keyboard 의 높이를 알 수 있다. 코드레벨로는 아래와 같다.
만약 PopupWindow 를 활용한다면 간략하게는 아래와 같이 구현할 수 있을 것이다.
각 단계와 코드를 보면 알겠지만 그리 깔끔하게 구현되지는 않는다. 개인적으로 native API 를 지원해줬으면 하는 바램이다. 😹 위 코드를 그대로 사용하기 보다는 각 과정의 원리를 이해하고 프로젝트의 요구사항에 맞게 상세 구현을 채워나가는 방향으로 진행하면 될 것 같다. 실제 프로덕트 레벨에서는 아직까지 사용 시 큰 이슈가 없었으나 혹시 엣지 케이스가 보이거나 더 좋은 방법이 있다면 꼭 공유해주셨으면 좋겠다. 🙌 참고사항
|