✨ 오늘 공부한 것
- 알고리즘 마법의 엘리베이터 풀이 - 스탠다드반 과제 마무리
카카오톡이나 채팅앱들을 보면 메시지를 입력하는 부분이 화면 하단에 존재한다. 입력창을 눌렀을 때 키보드가 올라오면 메시지를 입력하는 부분도 같이 올라오는 형태로 많이 구현되어있다.
이걸 구현하는 방법으로는 여러가지가 있겠지만, 그중에서도 오늘 나는 2가지 정도만 알아보려고 한다.
"EditText 키보드 위에 고정"이라고 검색했을 때 가장 많이 나오는 방법이다. 간단하게 속성 몇 개 추가만 해주면 안드로이드가 알아서 키보드 외의 화면을 올리거나 줄여준다.
AndroidManifest.xml
<activity
android:name=".activity.DetailActivity"
android:exported="false"
android:windowSoftInputMode="adjustResize" />
원래는 android:windowSoftInputMode="adjustResize"
만 주면 적용이 되지만, 나는 루트 뷰가 ConstraintLayout이라 그런지 잘 적용되지 않았다. 따라서 루트 뷰에 추가적으로 android:fitsSystemWindows="true"
속성을 작성해주었다.
activity_detail.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main"
android:fitsSystemWindows="true">
키보드가 올라온 상태인지 아닌지를 알 수 있는 방법은 다양하겠지만, 나는 처음 보여지는 화면의 크기와 키보드가 올라왔을 때의 화면의 크기가 다르다는 점을 이용했다. 현재 보여지고 있는 화면이 처음 렌더링 됐을 때의 화면보다 작다면, 무언가에 가려졌다는 뜻이고 이 말은 곧 키보드가 올라왔다는 뜻이기도 하다! 이걸 구현하기 위해 viewTreeObserver의 GlobalLayoutListener를 사용해주었다.
사실 처음에는 constraintSet을 이용하지 않고, EditText의 y축 만을 움직였었는데 다른 뷰와의 제약 조건이 잘 적용되지 않는 이슈가 있었다. ConstraintLayout은 뷰와 뷰 사이의 관계를 기준으로 화면이 구성되기 때문에 y축만 띡 바꾸는 게 아니라 뷰와 뷰 사이 관계까지 생각해서 적용을 해야된다고 한다. 이게 또 모든 뷰들에 대해 id 값이 있어야 하는 이유이기도 하다.
아무튼 코드는 키보드의 높이를 구한다음, EditText 아래쪽에 그만큼의 추가 마진을 주는 방식이다. 냅다 위치를 조정하는 것보단 마진으로 조절하는 게 더 간단하다고 한다.
private fun handleInputChat() {
val rootView = findViewById<ConstraintLayout>(R.id.main)
rootView.viewTreeObserver.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener {
private var isKeyboardShown = false
override fun onGlobalLayout() {
val r = Rect()
rootView.getWindowVisibleDisplayFrame(r)
val heightDiff = rootView.bottom - r.bottom
isKeyboardShown = heightDiff > 100
val constraintSet = ConstraintSet()
constraintSet.clone(rootView)
constraintSet.setMargin(
R.id.layout_chat,
ConstraintSet.BOTTOM,
if (isKeyboardShown) heightDiff else 20
)
constraintSet.applyTo(rootView)
}
})
}