20230823 RecyclerView

기메단·2023년 8월 23일
1

TIL

목록 보기
25/44

RecyclerView

RecyclerView의 구성요소 

1. Adapter (필수) : 
항목을 구성하는 역할 
데이터와 RecyclerView 사이의 연결을 위한 객체 

2. ViewHolder (필수) : 
항목에 필요한 뷰 객체를 가지는 역할
RecyclerView의 개념을 적용하기위해선 스크롤 해서 위로 올라간 
View를 재활용하기 위해서 이 View를 기억하고 있어야 한다. 
ViewHolder가 그 역할을 함.

3. LayoutManager (필수) : 항목을 배치하는 역할 
4. ItemDecoration (옵션) : 항목을 꾸미기 위한 역할 
5. ItemAnimation (옵션)
main.xml 위젯 변경
RecyclerView를 만들어주기 위해 메인화면 레이아웃에서 위젯을 RecyclerView로 변경한다. 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/recycler"/>

</LinearLayout>
item.xml

그 다음에 RecyclerView에서 나타낼 item이라는 layout 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/ex1"
        />
    <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="@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/black"
            android:textSize="@dimen/list_item_text_size2"
            android:padding="@dimen/list_item_padding"
            android:hint="Age"
            />
    </LinearLayout>

</LinearLayout>
data class
항목 뷰에 표시할 데이터를 정의한 MyItem 클래스 정의 
data class MyItem(val aIcon:Int, val aName:String, val aAge:String) {
}
* 데이터 클래스는 데이터를 다루는데 최적화된 클래스로 
equals(), hashCode(), toString(), copy(), componentN() 
5가지 유용한 함수들을 내부적으로 자동으로 생성해준다. 
Adapter
앞서 정의한 MyItem 타입의 객체들을 MutableList로 관리하는 MyAdapter 클래스를 RecyclerView.Adapter에 파생하여 정의 
package com.example.recyclerview

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.recyclerview.databinding.ActivityMainBinding
import com.example.recyclerview.databinding.ItemBinding

class MyAdapter(val mItems: MutableList<MyItem>) : RecyclerView.Adapter<MyAdapter.Holder>() {

    interface ItemClick {
        fun onClick(view : View, position : Int)
    }

    var itemClick : ItemClick? = null
    
	// 항목의 뷰를 가지는 ViewHolder를 준비하기 위해 자동 호출 
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
        val binding = ItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return Holder(binding)
    }
	
    // ViewHolder의 뷰에 데이터를 출력하기 위해서 자동 호출 
    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
    }
    
	// 항목 id를 항목의 위치로 간주함
    override fun getItemId(position: Int): Long {
        return position.toLong()
    }
    
	// MyAdapter 클래스가 관리하는 항목의 개수를 판단하기 위해 자동 호출
    override fun getItemCount(): Int {
        return mItems.size
    }
	
    // ViewHolder는 RecyclerView.ViewHolder를 상속받아 작성
    inner class Holder(val binding: ItemBinding) : RecyclerView.ViewHolder(binding.root) {
        val iconImageView = binding.iconItem
        val name = binding.textItem1
        val age = binding.textItem2
    }
}
여기서 inner class란. 
자바에서는 A클래스 안에 B클래스를 정의하면 B클래스는 자동으로 A클래스의 내부 클래스가 되어서
A클래스 안의 객체를 참조할 수 있다. 코틀린에서는 반대이고, 기본적으로 중첩 클래스가 된다. 
내부 클래스로 만들기 위해서는 inner 키워드를 사용하여 클래스를 선언해야 한다. 
mainActivity
package com.example.recyclerview

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.recyclerview.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding // viewBinding 

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // 데이터 원본 준비
        val dataList = mutableListOf<MyItem>()
        dataList.add(MyItem(R.drawable.ex1, "Bella", "1"))
        dataList.add(MyItem(R.drawable.ex2, "Charlie", "2"))
        dataList.add(MyItem(R.drawable.ex3, "Daisy", "1.5"))
        dataList.add(MyItem(R.drawable.ex4, "Duke", "1"))
        dataList.add(MyItem(R.drawable.ex5, "Max", "2"))
        dataList.add(MyItem(R.drawable.ex6, "Happy", "4"))
        dataList.add(MyItem(R.drawable.ex7, "Luna", "3"))
        dataList.add(MyItem(R.drawable.ex8, "Bob", "2"))
        dataList.add(MyItem(R.drawable.ex1, "Bob", "2"))
        dataList.add(MyItem(R.drawable.ex2, "Bob", "2"))
        dataList.add(MyItem(R.drawable.ex3, "Bob", "2"))

        binding.recycler.adapter = MyAdapter(dataList)

		// RecyclerView에 Adapter와 LayoutManager를 등록시켜 화면에 출력
        val adapter = MyAdapter(dataList)
        binding.recycler.adapter = adapter 
        binding.recycler.layoutManager = LinearLayoutManager(this)

    }
}

이제 실행을 하면
짜잔

어렵지만,, RecyclerView가 현업에서 비율이 높게 쓰인다는데 그만큼 열심히 공부해야한다는거겠지?

그리고 오늘 팁을 얻었는데 여기서 LinearLayout을 중첩시켜놨는데 그럴 필요 없이 constraintlayout으로 더 깔끔하게 만들어주는게 좋다고 한다. 오늘 더 친해진 '친구'가 알려줬다(chatgpt 아님). 친구 생김 ㅎㅎ

2개의 댓글

comment-user-thumbnail
2023년 8월 24일

음 여기에 뭔가 댓글 달았던 기억이 나는데 사라져있는거 같아요
오늘 너무 감사했습니다!!

답글 달기
comment-user-thumbnail
2023년 8월 24일

역시 동료학습 효과 짱..! 저는 늘 튜터님 찾아갔었는데, 주변과도 얘기해봐야겠어요 잘 보고 갑니다 !

답글 달기