1. RecyclerView
1) 개념
- 안드로이드 앱에서 리스트 형태의 데이터를 표시하는 데 사용되는 위젯 (AdapterView를 표현하는 여러 방법 중 하나)
- 여러 아이템을 스크롤 가능한 리스트로 표현, 많은 아이템을 효율적으로 관리하고 보여줌 (세로, 가로 등)
- 한정적인 화면에 많은 데이터를 넣을 수 있는 view (view를 재활용해서 사용하겠다는 것)
2) ListView 와 RecyclerView
ListView | RecyclerView |
- 사용자가 스크롤할 때 마다 위에 있던 아이템은 삭제되고, 맨 아래의 아이템은 생성되길 반복 | - 사용자가 스크롤할 때 위에 있던 아이템이 재활용되어 아래로 이동, 재사용됨 |
- 삭제와 생성을 반복해 성능에 좋지 않음 | - 10개정도의 view만 만들고 10개를 재활용해 사용함 |
3) Adapter
- 데이터 테이블을 목록 형태로 보여주기 위해 사용됨
- 데이터를 다양한 형식의 리스트 형식으로 보여주기 위해 데이터와 RecyclerView 사이에 존재하는 객체
= 데이터와 RecyclerView 사이의 통신을 위한 연결체
//콘센트 멀티어댑터 st... 인풋은 동일하지만 아웃풋의 형태가 달라지는 것.
4) ViewHolder
- 화면에 표시될 데이터나 아이템들을 저장하는 역할
- (스크롤해서 위로 올라간 View를 재활용하기 위해 View를 기억해두는 역할)
2. 예제
1) 메인화면 레이아웃(ex. activity_main.xml)에 ListView 위젯을 RecyclerView 위젯으로 변경
- activity_main.xml에는 LinearLayout 안에 RecyclerView라는 위젯 하나만 들어가 있음.
<?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>
2) 어댑터 클래스 정의
- 앞서 정의한 MyItem 타입의 객체들을 Arrayist로 관리하는 MyAdapter 클래스를 Recyclerview.Adapter를 파생해 정의
//MyItem.kt
data class MyItem (val aIcon : Int, val aName : String, val aAge : String){}
//MyAdapter.kt
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.customitemview.databinding.ItemRecyclerviewBinding
//RecyclerView의 Adapter를 상속받을것임.
//인자로 MyItem들의 List를 넣어줌(샘플데이터의 리스트들)
class MyAdapter(val mItems: MutableList<MyItem>) : RecyclerView.Adapter<MyAdapter.Holder>() {
// 클릭이벤트를 MainActivity 에 넘기는 ...
//ItemClick이라는 인터페이스 만들기
// 실제로 함수는 onClick, 매개변수로 view랑 position이 들어가게...
// 그리고 메인액티비티로 이동
interface ItemClick {
fun onClick(view : View, position : Int)
}
var itemClick : ItemClick? = null
//어댑터가 만들어지면서 viewHolder도 만들어짐
// 홀더는 이런 식으로 만들거야 st... 홀더가 어떤 식으로 되어있는지는 아래 이너클래스에.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
//Holder 만들어주기!!
// 바인딩하고 inflate해서...
val binding = ItemRecyclerviewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
// Holder에 집어넣어주기. Hodlder를 생성하는 것!
return Holder(binding)
}
//onBindViewHolder가 8번 돌면서 mItems에 있던 8개의 샘플데이터가 하나하나 실행됨, 실행 결과에 보여줌
// 화면에 보이는 부분까지만 실행됨! 나머지는 스크롤해서 보여질 때 보이게 됨
// holder: Holder 안에 차례대로 들어오는 것.
// position: Int 는 0번째부터 들어오게 됨
override fun onBindViewHolder(holder: Holder, position: Int) {
//클릭이벤트 추가하는 부분
// 1. 이 안에서 인텐트로 다른 액티비티를 호출하는 방법
// 2. 이 MyAdapter에서 클릭 이벤트를 받고, 이 이벤트 받은 것을 메인액티비티로 넘겨서
// 실제로 클릭에 대한 이벤트 처리를 메인에서 하게 함
// 그러려면 MyAdapter과 MainActivity 사이에 통신할 수 있는 인터페이스가 필요함
// -> 윗부분에 interface ItemClick 부분 보기
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
}
//Holder는 이너클래스로 만들어짐...
// ItemRecyclerviewBinding 은 item_recyclerview.xml 에 연결됨
inner class Holder(val binding: ItemRecyclerviewBinding) : RecyclerView.ViewHolder(binding.root) {
//그 안에 있던 3가지들... 재활용할것임
val iconImageView = binding.iconItem
val name = binding.textItem1
val age = binding.textItem2
}
}
- 위에 쓰인 item_recyclerview.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="60dp"
android:layout_height="60dp"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:padding="8dp"
android:scaleType="centerCrop"
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/black"
android:textSize="20dp"
android:padding="4dp"
android:hint="Name"/>
<TextView
android:id="@+id/textItem2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:textSize="16dp"
android:padding="4dp"
android:hint="Age"/>
</LinearLayout>
</LinearLayout>
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// 데이터 원본 준비
// 보통 데이터는 데이터클래스로 만들어짐.
// 정보들을 담은 하나의 객체로 만들어 MyItem 클래스의 리스트 형태로 만들기
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)
//recyclerView를 사용하기 위해서는 adapter랑 viewHolder가 필요...
//adapter 클래스를 만들기 위해 MyAdapter 클래스 만들어줌
//어댑터를 하나 만들어서 그 안에 데이터를 집어넣음
val adapter = MyAdapter(dataList)
//어댑터에 집어넣어줌
binding.recyclerView.adapter = adapter
//레이아웃을 어떻게 구성할건지를...
binding.recyclerView.layoutManager = LinearLayoutManager(this)
// MyAdapter에서 받아서...
//어댑터의 itemClick(MyAdapter에서 ItemClick? 인터페이스 타입의 itemClick)에
// MyAdapter.ItemClick 타입의 object를 걸어주는 것
// MyAdapter에서 onBindViewHolder에서 setOnClickListener 밑의 itemClick?.onClick(it,position)이 발생되면
// it은 view(item_recyclerview.xml의 전체. 통.)가 되고,
// 그게 클릭되면 그것의 view와 position을 onClick의 매개변수로 넣어서 itemClick을 호출시킴.
// 콜백은 메인의 override fun onClick 부분으로 들어옴
adapter.itemClick = object : MyAdapter.ItemClick {
override fun onClick(view: View, position: Int) {
//dataList의 포지션의 aName을 가져옴
val name: String = dataList[position].aName
Toast.makeText(this@MainActivity," $name 선택!", Toast.LENGTH_SHORT).show()
}
}
}
}
// 주석부분 다시 읽어보기
'Android Studio' 카테고리의 다른 글
[Android 앱개발 숙련] 프래그먼트 예제 실습 (# 추가하기) (0) | 2024.04.11 |
---|---|
[Android 앱개발 숙련] 프래그먼트 Fragment - 개념 (# 추가하기) (0) | 2024.04.11 |
[Android 앱개발 숙련] 어댑터 뷰, 리스트 뷰, 그리드 뷰 (# 추가하기) (0) | 2024.04.09 |
[Android 앱개발 숙련] 뷰 바인딩 - 개념, 설정방법 (# 추가하기) (0) | 2024.04.09 |
안드로이드 스튜디오 TTS 관련 코드 (0) | 2024.04.08 |