Adapter View
1) 정의
- 여러 개의 항목을 다양한 형식으로 나열하고 선택할 수 있는 기능 제공하는 뷰
- 리스트 뷰 (List View) : 항목을 수직으로 나열
- 그리드 뷰 (Gird View) : 항목을 격자 형태로 나열
- 표시할 항목 데이터를 직접 관리 X, 어댑터라는 객체로부터 공급 받음

2) Adapter
- 데이터 관리, 데이터 원본과 어댑터 뷰 사이의 중계 역할
- 데이터 원본이 어댑터에 설정 + 어댑터 뷰에는 어댑터 설정

- getCount() : 현재 어댑터가 관리하는 데이터 항목의 총 개수
- getView() : 화면에 실제로 표시할 항목 뷰
- getItem() : 특정 위치의 항목을 선택했을 때, 선택된 항목
- getItemId() : 특정 위치의 항목을 선택했을 때. 항목 Id
3) Adapter 종류
- BaseAdapter : 어댑터 클래스의 공통 구현 (기본)
- ArrayAdapter : 객체 배열이나 리소스에 정의된 배열로부터 데이터 공급 받음
- CursorAdapter : 데이터베이스로부터 데이터 공급 받음
- SimpleAdatper : 데이터를 Map(키, 값) 리스트로 관리
1. ListView
: 어댑터 뷰 대표 위젯, 복수 개의 항목 수직으로 표시

1) 리스트 뷰 생성 방법
메인 화면 레이아웃에 ListView 위젯 정의
- res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
어댑터 객체 설정
- 데이터 원본이 배열인 경우 ArrayAdapter 객체 사용
- ArrayAdapter(Context context, int resource, int textViewResourceId, T[] objects)
- context : 현재 context
- object : 어댑터로 공급될 데이터 (단순 배열)
- resource

- MainActivity : ArrayAdapter 객체 생성
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// 데이터 원본 준비
val items = arrayOf<String?>("item1", "item2", "item3", "item4", "item5", "item6", "item7", "item8", "item5", "item6", "item7", "item8", "item5", "item6", "item7", "item8", "item5", "item6", "item7", "item8")
//어댑터 준비 (배열 객체 이용, simple_list_item_1 리소스 사용
val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, items)
}
}
ListView 객체에 어댑터 연결
- MainActivity : ArrayAdapter 객체 연결
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// 데이터 원본 준비
val items = arrayOf<String?>("item1", "item2", "item3", "item4", "item5", "item6", "item7", "item8", "item5", "item6", "item7", "item8", "item5", "item6", "item7", "item8", "item5", "item6", "item7", "item8")
//어댑터 준비 (배열 객체 이용, simple_list_item_1 리소스 사용
val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, items)
// 어댑터를 ListView 객체에 연결
binding.listView.adapter = adapter
}
}
2. GridView
: 2차원 스크롤 가능한 그리드에 항목 표시

1) 그리드 뷰 생성 방법
메인 화면 레이아웃에 GridView 위젯 정의
- res/layout/activity_main.xml
- android:columnWidth : 그리드 항목 하나의 폭
- android:numColumns=“auto_fit” : 열의 폭과 화면 폭을 바탕으로 자동 계
- android:verticalSpacing : 항목 간의 간격 설정
- android:stretchMode=“columnWidth”: 열 내부의 여백을 폭에 맞게 채움
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="100dp"
android:numColumns="auto_fit"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"
/>
ArrayAdapter 객체 생성 + 연결
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// 데이터 원본 준비
val items = arrayOf<String?>("item1", "item2", "item3", "item4", "item5", "item6", "item7", "item8", "item5", "item6", "item7", "item8", "item5", "item6", "item7", "item8", "item5", "item6", "item7", "item8")
//어댑터 준비 (배열 객체 이용, simple_list_item_1 리소스 사용
val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, items)
// 어댑터를 GridView 객체에 연결
binding.gridView.adapter = adapter
}
}
3. Custom View
: 어댑터 뷰의 항목에 이미지나 문자열을 포함하는 임의의 뷰 넣음

1) 커스텀 뷰 생성 방법
커스텀 항목 xml 레이아웃 정의
- item.xml
<?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="wrap_content"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/iconItem"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:scaleType="centerCrop"
android:padding="@dimen/icon_padding"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:src="@drawable/sample_0"
/>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2">
<TextView
android:id="@+id/textItem1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorAccent"
android:textSize="@dimen/list_item_text_size1"
android:padding="@dimen/list_item_padding"
android:hint="Name"
/>
<TextView
android:id="@+id/textItem2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorPrimary"
android:textSize="@dimen/list_item_text_size2"
android:padding="@dimen/list_item_padding"
android:hint="Age"
/>
</LinearLayout>
</LinearLayout>
- res/values/dimens.xml : item.xml의 속성 값을 정의
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="list_item_text_size1">20dp</dimen>
<dimen name="list_item_text_size2">16dp</dimen>
<dimen name="list_item_padding">4dp</dimen>
<dimen name="icon_size">60dp</dimen>
<dimen name="icon_padding">8dp</dimen>
</resources>
항목 관련 데이터클래스 정의
data class MyItem(val aIcon:Int, val aName:String, val aAge:String) {}
어댑터 클래스 정의
- 앞서 정의한 MyItem 타입의 객체들을 ArrayList로 관리하는 BaseAdapter 사용
package com.android.customitemview
class MyAdapter(val mContext: Context, val mItems: MutableList<MyItem>) : BaseAdapter() {
// MyAdapter 클래스가 관리하는 항목의 총 개수를 반환
override fun getCount(): Int {
return mItems.size
}
// MyAdapter 클래스가 관리하는 항목의 중에서 position 위치의 항목을 반환
override fun getItem(position: Int): Any {
return mItems[position]
}
// 항목 id를 항목의 위치로 간주함
override fun getItemId(position: Int): Long {
return position.toLong()
}
// position 위치의 항목에 해당되는 항목뷰를 반환하는 것이 목적임
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
var convertView = convertView
if (convertView == null) convertView = LayoutInflater.from(parent?.context).inflate(R.layout.item, parent, false)
val item : MyItem = mItems[position]
// convertView 변수로 참조되는 항목 뷰 객체내에 포함된 객체를 id를 통해 얻어옴
val iconImageView = convertView?.findViewById<View>(R.id.iconItem) as ImageView
val tv_name = convertView.findViewById<View>(R.id.textItem1) as TextView
val tv_age = convertView.findViewById<View>(R.id.textItem2) as TextView
// 어댑터가 관리하는 항목 데이터 중에서 position 위치의 항목의 객체를 헤딩 힝목에 설정
iconImageView.setImageResource(item.aIcon)
tv_name.text = item.aName
tv_age.text = item.aAge
return convertView
}
}
메인 화면 xml 정의
- activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
어댑터 객체 생성 + 연결
- 데이터 ArrayList 객체 준비
- MyAdapter 객체 생성 + 연결
package com.android.customitemview
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// 데이터 원본 준비
val dataList = mutableListOf<MyItem>()
dataList.add(MyItem(R.drawable.sample_0, "Bella", "1"))
dataList.add(MyItem(R.drawable.sample_1, "Charlie", "2"))
dataList.add(MyItem(R.drawable.sample_2, "Daisy", "1.5"))
dataList.add(MyItem(R.drawable.sample_3, "Duke", "1"))
dataList.add(MyItem(R.drawable.sample_4, "Max", "2"))
dataList.add(MyItem(R.drawable.sample_5, "Happy", "4"))
dataList.add(MyItem(R.drawable.sample_6, "Luna", "3"))
dataList.add(MyItem(R.drawable.sample_7, "Bob", "2"))
// 어댑터 생성 및 연결
binding.listView.adapter = MyAdapter(this, dataList)
// 항목 클릭 이벤트 처리
binding.listView.setOnItemClickListener{ parent, view, position, id ->
val name: String = (binding.listView.adapter.getItem(position) as MyItem).aName
Toast.makeText(this," $name 선택!", Toast.LENGTH_SHORT).show()
}
}
}
3. Recycler View
: 한정적인 화면에 많은 데이터를 넣을 수 있는 View (View 사용해 재활용)

1) ListView와 RecyclerView

- ListView
- 스크롤 할 때마다 위에 아이템 삭제, 맨 아래 아이템 생성
- 아이템이 100개면 100개 삭제, 생성 → 성능 별로 좋지 않음
- RecyclerVIew
- 스크롤 할 때, 위에 있던 아이템 아래로 이동해 재사용
- 아이템이 100개여도 10개 정도의 View만 만들고 10개를 재활용해 사용
2) Adapter, ViewHolder
- Adapter : 데이터 테이블을 목록 형태로 보여주기 위해 사용
- ViewHolder : 화면에 표시될 데이터나 아이템 저장하는 역할 (재활용하기 위한 View)
3) Recycler View 생성 방법
커스텀 항목 xml 레이아웃 정의
- item.xml
<?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="wrap_content"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/iconItem"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:scaleType="centerCrop"
android:padding="@dimen/icon_padding"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:src="@drawable/sample_0"
/>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2">
<TextView
android:id="@+id/textItem1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorAccent"
android:textSize="@dimen/list_item_text_size1"
android:padding="@dimen/list_item_padding"
android:hint="Name"
/>
<TextView
android:id="@+id/textItem2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorPrimary"
android:textSize="@dimen/list_item_text_size2"
android:padding="@dimen/list_item_padding"
android:hint="Age"
/>
</LinearLayout>
</LinearLayout>
- res/values/dimens.xml : item.xml의 속성 값을 정의
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="list_item_text_size1">20dp</dimen>
<dimen name="list_item_text_size2">16dp</dimen>
<dimen name="list_item_padding">4dp</dimen>
<dimen name="icon_size">60dp</dimen>
<dimen name="icon_padding">8dp</dimen>
</resources>
메인화면 레이아웃 생성
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
어댑터 클래스 정의
- RecyclerView Adapter 사용
class MyAdapter(val mItems: MutableList<MyItem>) : RecyclerView.Adapter<MyAdapter.Holder>() {
//외부에서 함수 정의하기 위해 인터페이스 사용
interface ItemClick {
fun onClick(view : View, position : Int)
}
//인터페이스를 구현한 객체 참조 : 실제로 아이템이 클릭되었을 때 실행될 콜백 함수 구현
var itemClick : ItemClick? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val binding = ItemRecyclerviewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return Holder(binding)
}
override fun onBindViewHolder(holder: Holder, position: Int) {
holder.itemView.setOnClickListener { //클릭이벤트추가부분
itemClick?.onClick(it, position)
}
holder.iconImageView.setImageResource(mItems[position].aIcon)
holder.name.text = mItems[position].aName
holder.age.text = mItems[position].aAge
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItemCount(): Int {
return mItems.size
}
inner class Holder(val binding: ItemRecyclerviewBinding) : RecyclerView.ViewHolder(binding.root) {
val iconImageView = binding.iconItem
val name = binding.textItem1
val age = binding.textItem2
}
}
MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// 데이터 원본 준비
val dataList = mutableListOf<MyItem>()
dataList.add(MyItem(R.drawable.sample_0, "Bella", "1"))
dataList.add(MyItem(R.drawable.sample_1, "Charlie", "2"))
dataList.add(MyItem(R.drawable.sample_2, "Daisy", "1.5"))
dataList.add(MyItem(R.drawable.sample_3, "Duke", "1"))
dataList.add(MyItem(R.drawable.sample_4, "Max", "2"))
dataList.add(MyItem(R.drawable.sample_5, "Happy", "4"))
dataList.add(MyItem(R.drawable.sample_6, "Luna", "3"))
dataList.add(MyItem(R.drawable.sample_7, "Bob", "2"))
binding.recyclerView.adapter = MyAdapter(dataList)
val adapter = MyAdapter(dataList)
binding.recyclerView.adapter = adapter
binding.recyclerView.layoutManager = LinearLayoutManager(this)
//인터페이스 재정의
adapter.itemClick = object : MyAdapter.ItemClick {
override fun onClick(view: View, position: Int) {
val name: String = dataList[position].aName
Toast.makeText(this@MainActivity," $name 선택!", Toast.LENGTH_SHORT).show()
}
}
}
}