Android

Android studio_ 6. RecyclerView

아이른 2024. 2. 26. 21:00

1. RecyclerView

  • 리스트 형태의 데이터를 표시하는데 사용되는 위젯
  • 여러 아이템을 스크롤 가능한 리스트로 표현하며, 많은 아이템을 효율적으로 관리하고 보여주는 역할
  • 한정적인 화면에 많은 데이터를 넣을 수 있는 View
  • View를 재활용해서 사용한다는 특징

2. RecyclerView 사용법

  • Adapter
    • 데이터 테이블을 목록 형태로 보여주기 위해 사용
    • 데이터와 recyclerview 사이의 통신을 위한 연결체
  • ViewHolder
    • 화면에 표시될 데이터나 아이템들을 저장하는 역할
    • 스크롤 해서 위로 올라간 View를 재활용하기 위해서 이 View를 기억하고 있는 역할

3. 활용 예제

활용 1. 리사이클러 뷰를 이용하여 아래의 화면과 같이 만들기

① 모델 객체 만들기

//Profiles.kt

class Profiles(val gender:Int, val name:String, val age:Int, val job:String)

 

가공 받을 형식.xml 

 

더보기
<?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:layout_width="match_parent"
    android:layout_height="wrap_content">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <ImageView
            android:id="@+id/iv_profile"
            android:layout_width="100dp"
            android:layout_height="100dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:srcCompat="@drawable/woman" />

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:layout_marginTop="10dp"
            android:text="이름"
            android:textSize="20sp"
            android:textStyle="bold"
            app:layout_constraintStart_toEndOf="@id/iv_profile"
            app:layout_constraintTop_toTopOf="@id/iv_profile" />

        <TextView
            android:id="@+id/tv_age"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="20dp"
            android:text="20"
            android:textColor="#F44336"
            android:textSize="20sp"
            android:textStyle="bold"
            app:layout_constraintStart_toEndOf="@id/tv_name"
            app:layout_constraintTop_toTopOf="@id/tv_name" />

        <TextView
            android:id="@+id/tv_job"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:text="직업"
            android:textSize="20sp"
            android:textStyle="bold"
            app:layout_constraintBottom_toBottomOf="@id/iv_profile"
            app:layout_constraintStart_toStartOf="@id/tv_name" />


    </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

 

③ RecyclerView.Adapter 연결 : 데이터 전체를 관리

③-① ViewHolder 연결 : recyclerview의 아이템 하나하나를 관리 

 

import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView

class ProfileAdapter(val profileList:ArrayList<Profiles>) //Profiles를 리스트화
: RecyclerView.Adapter<ProfileAdapter.CustomViewHolder>() { //RecyclerView.Adapter 속성을 상속
    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): ProfileAdapter.CustomViewHolder {
        TODO("Not yet implemented")
    }

    override fun onBindViewHolder(holder: ProfileAdapter.CustomViewHolder, position: Int) {
        TODO("Not yet implemented")
    }

    override fun getItemCount(): Int {
        TODO("Not yet implemented")
    }
	
    //ViewHolder    
    class CustomViewHolder {

    }
}

 

④-① 뷰 홀더 구현

//뷰를 연결할 때 사용

/*
홀더의 생성자에 아이템 레이아웃을 inflate 한 레이아웃 클래스로 두었지만, 
class CustomViewHolder(itemView: View):RecyclerView.ViewHolder(itemView) {
    val gender = itemView.findViewById<ImageView>(R.id.iv_profile)
    val name = itemView.findViewById<TextView>(R.id.tv_name)
    val age = itemView.findViewById<TextView>(R.id.tv_age)
    val job = itemView.findViewById<TextView>(R.id.tv_job)
}
여러개의 데이터를 findViewById()를 통해 item을 매치 시킨다면 Hight Cost, 
그렇기 때문에 뷰 객체를 ViewHolder에 보관함으로써 findViewById()와 같은 반복적인 
호출 메소드를 줄여 속도 개선
*/

class MyViewHolder(private var binding:ListItemBinding):RecyclerView.ViewHolder(binding.root){
//list_item.xml > ListItemBinding
    val gender = binding.ivProfile
    val name = binding.tvName
    val age = binding.tvAge
    val job = binding.tvJob
}

 

④-② 기술 구현

  • onCreateViewHolder : Viewholder을 새로 만들때 마다 호출
    • ViewHolder와 연결된 view 생성 및 초기화하고, 데이터에 바인딩 된 상태가 아니기 때문에 뷰의 콘텐츠는 채우지 않음  

  • 3개의 인자를 받는 inflate() 사용 
    • 각각의 홀더가 부분부분 쓰여지기 때문에 개별 아이템이 view의 정보와 함께 목록 일부에 표시 
    • param1 : LayoutInflater를 넘기는 것이 없기 때문에 LayoutInflater.from(parent.context)를 사용하여 ViewGroup과 연결된 엑티비티의 context 가지고 옴
    • param2 : parent
    • param3 : false
    • 4주차_ SNS 앱 2. LayoutInflater (tistory.com) 참고
    override fun onCreateViewHolder(parent: ViewGroup,viewType: Int)
    : ProfileAdapter.CustomViewHolder {
        val binding = ListItemBinding.inflate(LayoutInflater.from(parent.context),parent,false)
        return  CustomViewHolder(binding)
        //View를 생성하고 ViewHolder에 View를 전달
    }
    /*
    binding 미사용 시,
        override fun onCreateViewHolder(parent: ViewGroup,viewType: Int)
    : ProfileAdapter.CustomViewHolder {
        val binding = LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)
        return  CustomViewHolder(binding)
    }
    */
  • onBindViewHolder : ViewHolder를 데이터와 연결할 때 호출
  • getItemCount : 데이터 항목의 총 개수를 반환
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

class ProfileAdapter(val profileList:ArrayList<Profiles>) 
: RecyclerView.Adapter<ProfileAdapter.CustomViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup,viewType: Int)
    : ProfileAdapter.CustomViewHolder {
        val binding = ListItemBinding.inflate(LayoutInflater.from(parent.context),parent,false)
        return  CustomViewHolder(binding)
    }

    override fun onBindViewHolder(holder: ProfileAdapter.CustomViewHolder, position: Int) {
        holder.gender.setImageResource(profileList.get(position).gender)//현재 클릭한 포지션 위치
        holder.name.text = profileList.get(position).name
        holder.age.text = profileList.get(position).age.toString()
        holder.job.text = profileList.get(position).job
    }

    override fun getItemCount(): Int {
        return profileList.size
    }
    //코드량 줄일 때: override fun getItemCount() = profileList.size 

class MyViewHolder(private var binding:ListItemBinding):RecyclerView.ViewHolder(binding.root){
    val gender = binding.ivProfile
    val name = binding.tvName
    val age = binding.tvAge
    val job = binding.tvJob
    }
}

 

⑤ activity_main.xml

더보기
<?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:layout_width="match_parent"
    android:layout_height="match_parent">


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_profile"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

⑥ ActivityMain.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 profileList = arrayListOf(
            Profiles(R.drawable.man, "김철수",20, "의사"),
            Profiles(R.drawable.woman, "김영희", 22, "간호사"),
            Profiles(R.drawable.man, "박민수",35, "변호사"),
            Profiles(R.drawable.woman, "김수영", 25, "조무사"),
            Profiles(R.drawable.man, "박영수",20, "세무사"),
            Profiles(R.drawable.woman, "한소의", 36, "회계사"),
            Profiles(R.drawable.man, "박철민",35, "개발자")
        )
        binding.rvProfile.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
        //리사이클러뷰의 레이아웃 구성 방법
        binding.rvProfile.setHasFixedSize(true)
        //리사이클러뷰 성능 개선 방안
        binding.rvProfile.adapter = ProfileAdapter(profileList)
        
        /*
        val adapter = ProfileAdapter(profileList)
        binding.rvProfile.adapter = adapter
        binding.rvProfile.layoutManager = LinearLayoutManager(this)
        */
    }
}
  • layoutManager을 MainActivity에서 설정할 수 있지만 activity_main.xml 에서도 가능

'Android' 카테고리의 다른 글

Android Studio_ 7. View binding  (0) 2024.03.27
Android studio_ Values Resource File 사용  (0) 2024.03.26
Android studio_ 5. Shared Preferences  (0) 2024.02.21
Android studio_ 4. NavigationView  (1) 2024.02.13
Android studio_ 3. ListView, GridView  (1) 2024.02.09