항상 스크롤 뷰는 헷갈린다.
다이얼로그 내에 있는 스크롤 뷰에 대해 알아보겠다.
sv_cont 부분이 스크롤이 되는 부분이고 안에 있는 내용들은 주어지는 데이터 값에 따라 view.visible, gone 처리가 된다.
문제는 스크롤 뷰가 잘 작동하려면 높이가 0dp 되어야한다는 점이고, 스크롤이 되게 하고자 다음과 같이 스크롤 뷰를 정의했다.
<androidx.core.widget.NestedScrollView
android:id="@+id/sv_cont"
android:layout_width="0dp"
android:layout_height="wrap_content" <!-- 문제되는 부분 -->
android:paddingBottom="26dp"
android:fillViewport="true"
app:layout_constraintTop_toBottomOf="@+id/btn_close"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
왜 높이가 wrap_content로 되어있냐 함은...
처음에는 위아래 제약조건을 걸기 위해서 높이를 0dp 위아래로 줬었다.
근데 계속 bottom을 못잡고 진짜 높이가 0dp가 되어서 scrollview부분이 아예 나타나지를 못하는 것이다.
평소 액티비티나 프래그먼트에서 bottom을 잡게 되면 화면의 바닥 부분을 잡겠지만, 이건 다이얼로그기 때문에 부모뷰까지 높이가 wrap_content 가 되어있다.
그래서 bottom이 명확히 어디까지인지를 모르니 스크롤뷰가 bottom을 못잡고 찐 높이가 0dp가 되어 보이지가 않는셈..
저 파란색 줄 영역이 스크롤 뷰 부분이고 안에 이로 인해 스크롤 뷰 안 내용이 보이지 않고 있다.
높이를 정해버리면 보이긴 하겠지만, 보여지는 뷰는 데이터에 따라서 컨텐츠 높이가 달라진다.
이를 해결하기 위해 스크롤 뷰의 높이를 wrap_content로 설정했다.
그랬더니 내용들이 다 보이기는 하는데, 문제는 글자크기를 키워서 스크롤 범위가 되면 제약조건이 위아래 높이가 넘치게 되면서
버튼 - 내용 간의 영역들이 침범하게 되는 것이다...
스크롤 뷰를 원하는 영역만큼 제대로 설정해주려면
위.아래 제약 조건 설정 -> 어디부터 어디까지 하게 할 것인 지 정해주고, 높이를 0dp로 설정해줘야한다.
그래서 스크롤 범위가 되는 높이인 최대 높이를 기준으로
스크롤 뷰의 높이를 wrap_content로 설정할 것인 지 , 0dp로 설정할 것인 지 정해줘야겠다고 생각했다.
이 말은 즉슨 스크롤이 필요하지 않는 경우라면 wrap_content, 필요한 경우라면 0dp로 설정해야한다는 것이다.
구현 스텝
1. 너비와 높이는 화면 크기의 퍼센트로 정해준다. (dp로 설정해도 상관은 없을 것 같다.)
2. 안에 그려지는 컴포넌트의 높이가 최대 높이인 0.89를 넘어서지 않는다면 scrollview의 높이는 똑같이 wrap_content로 설정
3. 최대 높이를 넘어선다면(스크롤뷰가 필요한 상황) 스크롤뷰가 위아래 제약조건에 알맞게 작동될 수 있도록 높이를 0dp로 설정 & 높이를 최대 높이인 0.89로 정해줬다. 높이가 정해짐으로써 bottom이 어딘 지를 알게되니 스크롤뷰도 위아래 제약조건에 맞게 잘 작동할 수 있는 셈이다....!
하도록 해줬더니, 디스플레이 설정(글자, 화면)에 맞게 잘리는 부분 없이 스크롤 뷰가 필요할 때는 제약조건에 맞게. 필요 없는 짧은 높이면 스크롤 뷰 없이 잘 작동해줬다.
코드는 이러하다.
val window = dialog?.window ?: return
val maxHeight = (resources.displayMetrics.heightPixels * 0.89).toInt()
val width = (resources.displayMetrics.widthPixels * 0.89).toInt()
window.setLayout(width, ViewGroup.LayoutParams.WRAP_CONTENT)
window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
// 이후 높이 측정해서 제한 적용
val decorView = window.decorView
decorView.viewTreeObserver.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
decorView.viewTreeObserver.removeOnGlobalLayoutListener(this)
if (decorView.height > maxHeight) {
binding.svCont.layoutParams = binding.svCont.layoutParams?.apply {
height = 0
}
binding.svCont.requestLayout()
window.setLayout(width, maxHeight)
}
}
})
요약
내용 크기 측정은 wrap_content 상태에서만 보임 | ✅ 초기엔 window height을 WRAP_CONTENT로 줘야 함 |
너무 크면 → 스크롤 되도록 maxHeight 적용 | ✅ window.setLayout(width, maxHeight) |
작으면 → scrollView도 wrap_content로 변경 | ✅ layoutParams.height = WRAP_CONTENT |
'Android' 카테고리의 다른 글
[Android] jetpack compose : State Hoisting(상태 호이스팅) (0) | 2025.03.07 |
---|---|
[Android] SMS Retriever 못 받아오는 오류 (0) | 2024.12.19 |
[Android] 앱 삭제 시에도 SharedPreference가 남아있는 현상 (0) | 2024.11.21 |
[Android] 안드로이드 앱 비동기 처리 및 interceptor (1) | 2024.11.20 |
[Android] FLAG_ACTIVITY_SINGLE_TOP 와 FLAG_ACTIVITY_CLEAR_TOP 차이점 (0) | 2024.11.19 |