안드로이드 앱을 개발하다 보면 ScrollView 안에 ListView를 배치해야 하는 경우가 종종 있습니다. 그런데 ScrollView는 자식 뷰의 높이를 제한 없이(unspecified) 측정하기 때문에, ListView가 자신의 실제 높이를 계산하지 못하고 첫 번째 항목 정도의 높이로 축소되어 버리는 문제가 자주 발생합니다.
이 글에서는 Kotlin을 사용해 ListView가 ScrollView 안에서 축소되지 않고 모든 항목을 온전히 표시하도록 만드는 방법을 단계별로 알아보겠습니다.
1단계 — 새 프로젝트 생성
Android Studio에서 File → New Project 메뉴로 이동한 뒤, 프로젝트 생성에 필요한 정보를 모두 입력하고 새 프로젝트를 만듭니다.
2단계 — activity_main.xml 작성
res/layout/activity_main.xml 파일에 아래 코드를 추가합니다.
예제
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="4dp"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="@+id/listView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
</ScrollView>3단계 — MainActivity.kt 작성
src/MainActivity.kt 파일에 다음 코드를 추가합니다. ArrayAdapter로 문자열 배열을 ListView에 연결한 뒤, 곧 만들 ListHelper의 getListViewSize() 함수를 호출하는 것이 핵심입니다.
import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.ListView
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
private val listViewArray = arrayOf(
"ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE",
"TEN", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen"
)
lateinit var list: ListView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
title = "KotlinApp";
list = findViewById(R.id.listView)
list.adapter = ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listViewArray)
ListHelper.getListViewSize(list)
}
}4단계 — ListHelper.kt 유틸리티 클래스 작성
새 Kotlin 클래스 ListHelper.kt를 만들고 아래 코드를 추가합니다. 이 클래스가 이 예제의 핵심입니다. 어댑터의 각 항목 뷰를 하나씩 가져와 measure()로 높이를 측정한 후, 항목 높이의 합에 구분선(divider) 높이를 더한 값을 ListView의 layoutParams.height에 지정함으로써 ListView가 전체 크기를 갖도록 강제합니다.
import android.util.Log
import android.widget.ListAdapter
import android.widget.ListView
object ListHelper {
fun getListViewSize(myListView: ListView) {
val myListAdapter: ListAdapter = myListView.adapter
?: //do nothing return null
return
//set listAdapter in loop for getting final size
var totalHeight = 0
for (size in 0 until myListAdapter.count) {
val listItem = myListAdapter.getView(size, null, myListView)
listItem.measure(0, 0)
totalHeight += listItem.measuredHeight
}
//setting listView item in adapter
val params = myListView.layoutParams
params.height =
totalHeight + myListView.dividerHeight * (myListAdapter.count - 1)
myListView.layoutParams = params
// print height of adapter on log
Log.i("height of listItem:", totalHeight.toString())
}
}5단계 — AndroidManifest.xml 작성
androidManifest.xml에 아래 코드를 추가합니다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="com.example.q11">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>앱 실행 및 결과 확인
이제 애플리케이션을 실행해 보겠습니다. 실제 안드로이드 기기가 컴퓨터에 연결되어 있다고 가정합니다. Android Studio에서 프로젝트의 액티비티 파일 중 하나를 연 뒤 툴바의 Run 아이콘
을 클릭하세요. 실행 옵션에서 본인의 모바일 기기를 선택하면, 기기 화면에 ListView의 모든 항목이 축소되지 않은 채 정상적으로 표시되는 것을 확인할 수 있습니다.

참고: 더 나은 대안
ListView를 ScrollView에 넣는 구조는 항목 뷰를 반복적으로 측정해야 하므로 성능 면에서 권장되지 않습니다. 최신 안드로이드 개발에서는 NestedScrollView + RecyclerView 조합을 사용하거나, 목록 하나만 필요하다면 RecyclerView(또는 ListView)가 스크롤을 직접 처리하도록 하는 것이 좋습니다. 다만 레거시 코드 유지보수 등 부득이한 상황에서는 위의 ListHelper 방식이 여전히 유용하게 활용될 수 있습니다.