인프런에서 강의를 듣던 중 ListView에 대한 내용이 나왔는데, 나에겐 어렵게 느껴져서 필기 겸 해서 작성해보려한다.

사진에서 보이듯, 흔히 볼 수 있는 리스트 그러니까 목록을 죽 나열해서 보여주는 녀석이라 보면 되겠다.

MainActivity에서 Adapter로 데이터를 전송
Adapter에서 listview_item.xml에 item(쉽게 목록 1줄)에 "a","b","c"를 하나씩 넣어준 후 이를 acitivity_main.xml의 ListView에 넣어준다.
res - layout-activity_main.xml에 ListView를 생성해주기
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ListView
android:id="@+id/mainListview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity가 있는 폴더에 이름을 ListViewAdapter 로 kotlin 파일을 생성.
package com.blueblue.listview_ex
class ListViewAdapter {
}
어떤 리스트를 받을지 입력
package com.blueblue.listview_ex
import android.widget.BaseAdapter
class ListViewAdapter(val List : MutableList<String>): BaseAdapter(){
}

빨간 줄 뜨는 곳에 alt+enter 눌러서 BaseAdapter로서 작동하게 하기 위해 import 및 코드 기입
package com.blueblue.listview_ex
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
class ListViewAdapter(val List : MutableList<String>): BaseAdapter() {
override fun getCount(): Int {
TODO("Not yet implemented")
}
override fun getItem(position: Int): Any {
TODO("Not yet implemented")
}
override fun getItemId(position: Int): Long {
TODO("Not yet implemented")
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
TODO("Not yet implemented")
}
}
getCount: ListView의 갯수, 이번엔 입력받는 list의 크기로 설정
getItem: item에 들어갈 리스트의 원소
getPosition: 해당 item이 가지게 될 Id
getView: ListView의 각 항목을 위한 뷰를 생성하고 반환하는 역할
res-layout에서 layout Resource File을 추가 생성

이름은 상관없으나, listview_item으로 생성.(배우고 있는 중이니까)
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.constraintlayout.widget.ConstraintLayout>
리스트의 각 아이템을 보여주는 공간으로 아래처럼 작성
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="80dp">
<TextView
android:id="@+id/listviewItem"
android:textSize="30sp"
android:layout_margin="5dp"
android:text="리스트뷰 아이템"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
getCount, getItem, getItemId에 사용할 리스트 사이즈와 원소, 아이템 id를 return 해주기
getView에서는 listview_item.xml을 가져와서 사용할 것임을 명시
ListViewAdapter에서 작성
package com.blueblue.listview_ex
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
class ListViewAdapter(val List : MutableList<String>): BaseAdapter() {
override fun getCount(): Int {
return List.size
}
override fun getItem(position: Int): Any {
return List[position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
var converView = convertView
if(converView == null){
converView = LayoutInflater.from(parent?.context).inflate(R.layout.listview_item, parent, false)
}
return converView!!
}
}
MainActivity에서 작성
package com.blueblue.listview_ex
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
val list_item = mutableListOf<String>()
list_item.add("A")
list_item.add("B")
list_item.add("C")
val adapter = ListViewAdapter(list_item)
}
}
리스트를 생성하고, 리스트에 "A","B","C" 를 각 원소로 기입 후
val listadapter = ListViewAdapter(list_item)
를 통해서 list_item을 MainActivity에서 Adapter 로 전달 완료.
남은 것은 listview_item.xml에서 activity_main.xml의 listview로 전달하는 과정!
val listview = findViewById<ListView>(R.id.mainListview)
로 ListView 중에서 mainListview를 id로 사용하고 있는 LIstView를 listview 변수에 입력.
해당 변수를
listview.adapter = listadapter
adapter를 이용해서 이전에 만들어준 listadapter를 사용
package com.blueblue.listview_ex
import android.os.Bundle
import android.widget.ListView
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
val list_item = mutableListOf<String>()
list_item.add("A")
list_item.add("B")
list_item.add("C")
val listview = findViewById<ListView>(R.id.mainListview)
val listadapter = ListViewAdapter(list_item)
listview.adapter = listadapter
}
}
그리고 run 해보면

코드를 다시 살펴보면
ListViewAdapter의 getView에서
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
var converView = convertView
if(converView == null){
converView = LayoutInflater.from(parent?.context).inflate(R.layout.listview_item, parent, false)
}
return converView!!
}
converView(convertView말고) 는 layout의 listview_item.xml
즉, listview_item.xml에 있는 TextView가 된다.
<TextView
android:id="@+id/listviewItem"
android:textSize="30sp"
android:layout_margin="5dp"
android:text="리스트뷰 아이템"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
그런데 여기에 데이터의 값을 이 TextView에 넣어주는 작업을 하지 않았으니 내 데이터로 목록이 뜨지 않음.
따라서 ListViewAdapter의 getView에
converView(null이 아님)에 속한 TextView중에 listviewItem이라는 녀석을 찾아서 title이라는 변수에 집어넣고, 이 title 즉, TextView의 text를 List[position] 으로 변경하겠다는
var title = converView!!.findViewById<TextView>(R.id.listviewItem)
title.text = List[position]
이 코드를 추가해서 데이터가 입력되도록 한다.
그러면 잘 나오는 것을 확인할 수 있다.


- MainActivity.kt에서 사용할 리스트가 있으시다!!!!
- activity_main.xml에 ListView를 생성!!!!
- 으아닛! 전달할 방법이 엄성.. adapter를 만들자!!! ListViewAdapter.kt 생성!(BaseAdapter를 통해 adapter로 사용)
- 메우, 리스트를 입력받았는데 얘 어떻게 보이게 할깝쇼? => listview_itme.xml을 만들어서 item을 생성하자!!!
- MainActivity.kt에서 adapter로 리스트를 전달전달영차영차!! 그리고, 연결시킬 ListView를 찾아서 연결하고, 출력준 비를 하라!!!!!
- ListViewAdapter.kt에서 MainActivity에서 하달하신 List를 적용하자!!! getView에서는 listview_item.xml을 연결시키고, 변환할 부분이 있으면 구현을 끝마치고, 반환하라!!!
- 완료ㅎ
package com.blueblue.listview_ex
import android.os.Bundle
import android.widget.ListView
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
val list_item = mutableListOf<String>()
list_item.add("A")
list_item.add("B")
list_item.add("C")
val listview = findViewById<ListView>(R.id.mainListview)
val listadapter = ListViewAdapter(list_item)
listview.adapter = listadapter
}
}
package com.blueblue.listview_ex
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.TextView
class ListViewAdapter(val List : MutableList<String>): BaseAdapter() {
override fun getCount(): Int {
return List.size
}
override fun getItem(position: Int): Any {
return List[position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
var converView = convertView
if(converView == null){
converView = LayoutInflater.from(parent?.context).inflate(R.layout.listview_item, parent, false)
}
var title = converView!!.findViewById<TextView>(R.id.listviewItem)
title.text = List[position]
return converView!!
}
}
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ListView
android:id="@+id/mainListview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="80dp">
<TextView
android:id="@+id/listviewItem"
android:textSize="30sp"
android:layout_margin="5dp"
android:text="리스트뷰 아이템"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>

package com.blueblue.listview_ex
data class ListViewModel (
var title : String = "",
var content : String = ""
)
이렇게 ListViewModel로 title과 content를 가진 모델을 사용해보자.
MainActivity.kt에서 사용되던 기존 코드는
val list_item = mutableListOf<String>()
list_item.add("A")
list_item.add("B")
list_item.add("C")
val listview = findViewById<ListView>(R.id.mainListview)
val listadapter = ListViewAdapter(list_item)
listview.adapter = listadapter
아래 처럼 model을 이용해서 list에 입력 시켜준다.
val list_item = mutableListOf<ListViewModel>()
list_item.add(ListViewModel("a","b"))
list_item.add(ListViewModel("c","d"))
list_item.add(ListViewModel("e","f"))
val listview = findViewById<ListView>(R.id.mainListview)
val listadapter = ListViewAdapter(list_item)
listview.adapter = listadapter
activity_main.xml에서는 굳이 바꿔줄 필요가 없다.
listview_item.xml이 TextView 하나만 가지고 있어서, model의 2가지 변수를 모두 사용할 수 없으니 TextView를 하나 더 생성.
<TextView
android:id="@+id/listviewItem"
android:textSize="30sp"
android:layout_margin="5dp"
android:text="리스트뷰 아이템"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
위 코드를 아래 코드처럼
<TextView
android:id="@+id/listviewItem"
android:textSize="30sp"
android:layout_margin="5dp"
android:text="리스트뷰 아이템"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/listviewItem2"
android:textSize="20sp"
android:layout_margin="5dp"
android:text="리스트뷰 아이템2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
ListViewAdapter.kt에서는 getView()를 수정해서 model에 있는 title과 content를 모두 이용할 수 있도록 listview_item.xml의 TextView와 각각 연결 후, 각각 입력.
기존 코드
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
var converView = convertView
if(converView == null){
converView = LayoutInflater.from(parent?.context).inflate(R.layout.listview_item, parent, false)
}
var title = converView!!.findViewById<TextView>(R.id.listviewItem)
title.text = List[position]
return converView!!
}
수정 코드
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
var converView = convertView
if(converView == null){
converView = LayoutInflater.from(parent?.context).inflate(R.layout.listview_item, parent, false)
}
var title = converView!!.findViewById<TextView>(R.id.listviewItem)
var content = converView!!.findViewById<TextView>(R.id.listviewItem2)
title.text = List[position].title
content.text = List[position].content
return converView!!
}
}
어렵다.... 만들고 싶은 앱 있는데 만들 수 있을까 흑흑흑흑흑...
안드로이드 스튜디오에서 리스트를 사용하기 위해서는 adapter를 이용해줘야 하며, 리스트의 각 item이 어떻게 생겼는지도 보여줄 xml파일도 만들어줘야한다.
그리고, 리스트에 여러개의 값이 들어갈 것이라면, model파일을 만들어서 입력받을 리스트 값을 입력해주고, 위에 말한 adapter를 이용해주고, item이 어떻게 생겼는지 보여줄 xml파일도 만들어 주면된다.
쓰고나니 그리 어렵지 않은 것처럼 보이네..
할 수 있드아아아아아아아