[ RecyclerView ]
: 안드로이드 앱에서 리스트 형태의 데이터를 표시하는 데 사용되는 위젯, 여러 아이템을 스크롤 가능한 리스트로 표현하며 많은 아이템을 효율적으로 관리하고 보여 주는 역할을 함.
- RecyclerView 는 한정적인 화면에 많은 데이터를 넣을 수 있는 View 임
- Recycle 을 해석하면 재활용하다라는 의미로 재사용을 하기 위해 사용됨
[ ListView 와 RecyclerView ]
ListView
- 사용자가 스크롤 할 때마다 위에 있던 아이템은 삭제되고 맨 아래의 아이템은 생성되는 것을 반복
- 아이템이 100개면 100개의 아이템들이 삭제되고 생성되는 것을 반복하여 성능이 좋지 않음
RecyclerView
- 사용자가 스크롤 할 때 위에 있던 아이템을 재활용하여 아래로 이동되기 때문에 재사용하게 됨
- 아이템이 100개여도 10개 정도의 View 만 만들고 10개를 재활용해서 사용함
- View 를 계속 만드는 ListView 의 단점을 보완하기 위해 생김
[ RecyclerView 사용법 ]
1) Adapter
- 데이터 테이블을 목록 형태로 보여 주기 위해 사용되는 것으로 데이터를 다양한 형식의 리스트 형식을 보여 주기 위해서 데이터와 RecyclerView 사이에 존재하는 객체
=> 데이터와 RecyclerView 사이의 통신을 위한 연결체
2) ViewHolder
- ViewHolder 란 화면에 표시될 데이터나 아이템들을 저장하는 역할을 함
- RecyclerView 의 개념을 적용하기 위해서 스크롤해서 위로 올라간 View를 재활용해야 하는데 이 때의 View 를 기억하고 있어야 하고 이 역할을 ViewHolder 가 함
3) RecyclerView 예제
먼저, 메안 화면에 대한 레이아웃 작업이 끝났다면 RecyclerView 가 들어갈 곳에 담길 item 의 UI 를 작업해 줘야 한다.
< item_recyclerview.xml >
recyclerview의 item들이 어떤 속성의 데이터들을 가지고 있을지 데이터 타입과 이름을 선언하는 데이터 클래스를 생성해 준다. 아래에서 companion object 로 다른 변수들을 생성해 준 이유는 멀티 뷰 타입 recyclerview 를 사용해 보기 위함이다.
< data.kt >
data class CardInfo(val type: Int, val name: String, val num: String, val data: String, val price: Double) {
companion object {
const val BLUE_TYPE = 0
const val SKY_TYPE = 1
const val ORANGE_TYPE = 2
}
}
메인 화면과 item 에 대한 전반적인 레이아웃 작업이 끝나고 데이터 클래스를 생성하여 데이터 타입을 설정했다면 Adapter를 만들어 줘야 한다. 어댑터를 만들 때는 필수적으로 오버라이딩 (재정의) 해야 하는 메소드들이 있다.
< MultiViewAdapter.kt >
class MultiViewAdapter(private val list: List<CardInfo>) : RecyclerView.Adapter<MultiViewAdapter.CardViewHolder>() {
interface ItemClick {
fun onClick(view: View, position: Int)
}
var itemClick : ItemClick? = null
// 뷰가 만들어질 때 호출되는 메소드
// 멀티 뷰 타입을 구현하기 위해서 when 절을 이용하여 viewType 에 따라 다른 item 을 화면에 출력하도록 했다
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MultiViewAdapter.CardViewHolder {
val view: View?
return when (viewType) {
CardInfo.BLUE_TYPE -> {
view = LayoutInflater.from(parent.context).inflate(R.layout.item_recyclerview, parent, false)
CardViewHolder(view)
}
CardInfo.SKY_TYPE -> {
view = LayoutInflater.from(parent.context).inflate(R.layout.item_recyclerview2, parent, false)
CardViewHolder(view)
}
CardInfo.ORANGE_TYPE -> {
view = LayoutInflater.from(parent.context).inflate(R.layout.item_recyclerview3, parent, false)
CardViewHolder(view)
}
else -> throw RuntimeException("알 수 없는 뷰 타입")
}
}
override fun getItemCount(): Int {
return list.size
}
override fun getItemViewType(position: Int): Int {
return list[position].type
}
// 뷰가 바인드 될 때 호출되는 메소드
// 뷰에 내용이 씌워질 때. 즉 스크롤을 내리거나 올릴 때
override fun onBindViewHolder(holder: MultiViewAdapter.CardViewHolder, position: Int) {
holder.itemView.setOnClickListener {
itemClick?.onClick(it, position)
}
holder.name.text = list[position].name
holder.number.text = list[position].num
holder.date.text = list[position].data
val decimalFormat = DecimalFormat("$#,###.00")
holder.price.text = decimalFormat.format(list[position].price)
}
// 어댑터 클래서 외부 혹은 내부에 RecyclerView.CardViewHolder 클래스를 상속하여 만듦
// 각 뷰들을 id 나 itemview 를 통해서 연결시킴
inner class CardViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val name: TextView = itemView.findViewById(R.id.tv_name)
val number: TextView = itemView.findViewById(R.id.tv_cardnum)
val date: TextView = itemView.findViewById(R.id.tv_date)
val price: TextView = itemView.findViewById(R.id.tv_balance)
init {
itemView.setOnClickListener {
itemClick?.onClick(it, adapterPosition)
}
}
}
}
어댑터에 대한 설정이 끝났다면 메인 액티티비티와 어댑터를 연결하는 작업, 데이터들을 추가하는 작업, 데이터를 보내는 작업 등 다양한 작업을 해 줘야 한다.
< MainActivity.kt >
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 = listOf(
CardInfo(
CardInfo.BLUE_TYPE,
"Anderson",
"2423 3581 9503 2412",
"21 / 24", 3100.30
),
CardInfo(
CardInfo.SKY_TYPE,
"Anderson",
"2423 3581 9503 2412",
"12 / 25",
3100.30
),
CardInfo(
CardInfo.ORANGE_TYPE,
"Anderson",
"2423 3581 9503 2412",
"21 / 24",
3100.30
)
)
// 데이터 리스트를 사용해 어댑터를 만듦
val adapter = MultiViewAdapter(dataList)
// 아이템이 클릭되었을 때 intent 와 bundle 을 사용해서 다음 액티비티로 데이터 전달
adapter.itemClick = object : MultiViewAdapter.ItemClick {
override fun onClick(view: View, position: Int) {
val selectedItem = dataList[position]
val intent = Intent(this@MainActivity, DetailActivity::class.java)
val bundle = Bundle().apply {
putString("name", selectedItem.name)
putString("num", selectedItem.num)
putString("date", selectedItem.data)
putDouble("price", selectedItem.price)
}
intent.putExtra("bundle", bundle)
startActivity(intent)
}
}
// 리사이클러뷰에 어댑터를 붙여주고 레이아웃 매니저를 성정해 줌
binding.recyclerView.adapter = adapter
binding.recyclerView.layoutManager = LinearLayoutManager(this)
}
}
[ 최종 결과물 ]
ㄴ> 화면 하단의 카드들이 recyclerview 를 사용한 것이다. 해당 item 들을 클릭하면 MainAcitivty 에서 DetailActivity 로 전환되며 해당 item 이 갖고 있는 데이터를 bundle 로 묶어 전달한다.
ㄴ> 해당 item 의 데이터가 DetailActivity 로 잘 넘어온 모습이다. intent의 putExtra() 를 사용해서 데이터를 전달하는 방법밖에 사용해 보지 않았는데 bundle 을 통해 putString, putDouble ... 등 타입으로 지정해서 데이터를 묶어서 전달하는 방식을 사용해 보니 훨씬 편리한 것 같다.
'Android' 카테고리의 다른 글
(Android Studio) - Dialog 사용하기 (0) | 2024.04.23 |
---|---|
(Android Studio) - 프래그먼트의 데이터 전달 (0) | 2024.04.17 |
(Android Studio) - Adapter View (0) | 2024.04.12 |
(Android Studio) - View Binding (0) | 2024.04.11 |
(Android Studio) - 다국어 지원 설정, strings.xml (1) | 2024.04.03 |