일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 안드로이드 생명주기
- 안드로이드
- android SharedPreferences
- android itemDecoration
- AAC
- ViewPager
- recyclerview
- MVC
- android startActivityForResult
- android recyclerview
- Android
- 코틀린
- 생명주기
- 안드로이드 ViewPager
- 안드로이드 자동로그인
- activity
- MVVM
- kotlin
- 안드로이드 Bottom Navigation
- 리사이클러뷰
- 안드로이드 RecyclerView
- andoid
- fragment
- Navigation
- android clipToPadding
- SharedPreferences
- Bottom Navigation
- MVP
- Today
- Total
my repository
Android :: RecyclerView 리사이클러뷰 사용법 본문
💡 RecyclerView
RecyclerView는 사용자가 관리하는 많은 수의 데이터 집합(Data Set)을 개별 아이템 단위로 구성하여 화면에 출력하는 뷰그룹(ViewGroup)이며, 한 화면에 표시되기 힘든 많은 수의 데이터를 스크롤 가능한 리스트로 표시해주는 위젯이다.
RecyclerView는 이름 그대로 View를 재활용하여 사용한다.
LayoutManager를 사용하여 다양한 뷰 배치를 표현할 수 있어서 유연하다는 장점이 있다.
- LinearLayoutManager : 세로/가로방향 배치
- GridLayoutManager : 바둑판 형식 배치
RecyclerView의 사용 방식은 다음과 같다.
📝 예제 : LinearLayoutManager
0. 라이브러리 추가 (build.gradle - app)
// 리사이클러뷰를 다루기 위한 라이브러리
implementation 'androidx.recyclerview:recyclerview:1.1.0'
// material 디자인 라이브러리
implementation "com.google.android.material:material:1.2.0-alpha05"
// 이미지 url 로딩 라이브러리
implementation "com.github.bumptech.glide:glide:4.10.0"
kapt "com.github.bumptech.glide:compiler:4.10.0"
// 동그란 이미지 커스텀 뷰 라이브러리
implementation 'de.hdodenhof:circleimageview:3.1.0'
1. ItemView (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:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
...>
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/img_profile"
android:layout_width="48dp"
android:layout_height="48dp"
... />
<TextView
android:id="@+id/tv_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
... />
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
... />
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageView
android:id="@+id/img_contents"
android:layout_width="0dp"
android:layout_height="0dp"
... />
</androidx.constraintlayout.widget.ConstraintLayout>
2. RecyclerView 배치
- 리사이클러뷰를 사용할 곳에 View를 배치하고, listitem에 앞서 만든 itemView를 넣어준다.
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_home"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:orientation="vertical"
android:paddingTop="6dp"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:clipToPadding="false"
tools:listitem="@layout/item_insta" />
3. Data class
- 데이터 형태를 정의하는 class를 생성한다.
- 예제에서 만든 item의 TextView 1개와 ImageView 2개에 들어갈 data를 저장할 class이다.
data class InstaData (
val userName : String,
val img_profile : String,
val img_contents : String
)
4. ViewHolder
- ViewHolder를 통해 받은 데이터를 뷰로 연결시켜준다.
- ViewHolder란 각 뷰들을 보관하는 홀더 객체이다. 각 뷰 객체를 ViewHolder에 보관함으로써 findViewById와 같이 반복적으로 호출되는 메서드를 효과적으로 줄여 속도를 향상시킨다.
class InstaViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val tv_username = itemView.findViewById<TextView>(R.id.tv_username)
val img_profile = itemView.findViewById<ImageView>(R.id.img_profile)
val img_contents = itemView.findViewById<ImageView>(R.id.img_contents)
// ViewHolder와 instaData 클래스의 각 변수를 연동하는 역할
fun bind(instaData: InstaData) {
tv_username.text = instaData.userName
Glide.with(itemView).load(instaData.img_profile).into(img_profile)
Glide.with(itemView).load(instaData.img_contents).into(img_contents)
}
}
5. Adapter
- RecyclerView에 표시될 아이템 뷰를 생성한다.
- Adapter는 필요에 따라 ViewHolder를 만들고, 데이터와 바인딩함으로써 ViewHolder를 특정 위치에 할당한다.
- RecyclerView의 Adapter에서 꼭 구현해야 하는 것은 다음과 같다.
메서드 | 설명 |
onCreateViewHolder(ViewGroup parent, int viewType) | viewType 형태의 아이템 뷰를 위한 뷰홀더 객체 생성 |
onBindViewHolder(ViewHolder holder, int position) | position에 해당하는 데이터를 뷰홀더의 아이템뷰에 표시 |
getItemCount() | 전체 아이템 갯수 리턴 |
class InstaAdapter(private val context : Context) : RecyclerView.Adapter<InstaViewHolder>() {
var datas = mutableListOf<InstaData>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): InstaViewHolder {
val view = LayoutInflater.from(context).inflate(R.layout.item_insta, parent, false)
return InstaViewHolder(view)
}
override fun getItemCount(): Int {
return datas.size
}
override fun onBindViewHolder(holder: InstaViewHolder, position: Int) {
holder.bind(datas[position])
}
}
onCreateViewHolder 메서드에서 LayoutInflater를 이용하여 item_insta.xml을 inflate 시킨다.
(참고) inflate란? xml에 쓰여있는 view의 정의를 실제 view객체로 만드는 역할
6. 마지막으로 데이터를 넣고, Adapter를 이용해서 RecyclerView에 띄어준다.
- loadDatas()에서 임의로 데이터를 만들어 어댑터에 추가시킨다.
- 데이터를 추가했으면 notifyDataSetChanged()를 통해 데이터가 갱신됨을 어댑터에 알려주어야 한다.
class HomeFragment : Fragment() {
lateinit var instaAdapter: InstaAdapter
val datas = mutableListOf<InstaData>()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_home, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
instaAdapter = InstaAdapter(view.context)
rv_home.adapter = instaAdapter // 리사이클러뷰의 어댑터를 instaAdapter로 지정해줌
rv_home.addItemDecoration(RecyclerDecoration(20))
loadDatas() // 데이터를 임의로 생성하고 어댑터에 전달
}
private fun loadDatas() {
datas.apply {
add(
InstaData(
userName = "userName",
img_profile = "이미지 파일 or 링크",
img_contents = "이미지 파일 or 링크"
)
)
add(
InstaData(
userName = "userName",
img_profile = "이미지 파일 or 링크",
img_contents = "이미지 파일 or 링크"
)
)
add(
InstaData(
userName = "userName",
img_profile = "이미지 파일 or 링크",
img_contents = "이미지 파일 or 링크"
)
)
instaAdapter.datas = datas
instaAdapter.notifyDataSetChanged() // 데이터가 갱신됨을 어댑터에 알려주는 역할
}
}
}
📝 예제 : GridLayoutManager
- GridLayoutManager(context, 한 줄에 들어가는 아이템 개수, RecyclerView.VERTICAL, false)
val myLayoutManager = GridLayoutManager(this, 3, RecyclerView.VERTICAL, false)
rv_toon.layoutManager = myLayoutManager
- DividerItemDecoration으로 아이템 사이 구분선을 추가할 수 있다.
- VERTICAL : 수직 구분선 / HORIZONTAL : 수평 구분선
val v_decoration = DividerItemDecoration(applicationContext, LinearLayoutManager.VERTICAL)
rv_toon.addItemDecoration(v_decoration)
val h_decoration = DividerItemDecoration(applicationContext, LinearLayoutManager.HORIZONTAL)
rv_toon.addItemDecoration(h_decoration)
💡 RecyclerView의 itemDecoration, clipToPadding
itemDecoration
ItemDecoration 클래스는 RecyclerView 내부에 있는 추상 클래스이다.
아이템 사이의 간격 조절, 구분선 추가 등에 사용할 수 있다.
1. RecyclerDecoration 클래스를 만들어 준다.
- getItemOffsets를 통해 recyclerView의 아이템에 여백을 설정해줄 수 있다.
class RecyclerDecoration(private val divHeight : Int) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
outRect.bottom = divHeight
}
}
2. 리사이클러뷰에 연결해준다.
rv_home.addItemDecoration(RecyclerDecoration(20))
clipToPadding
리사이클러뷰에 패딩을 줄 경우 스크롤 시에도 패딩 공간이 유지될 것이다.
이 때 clipToPadding="false" 라는 속성값을 이용하면 패딩공간을 스크롤 영역으로 활용할 수 있다.
<androidx.recyclerview.widget.RecyclerView
...
android:paddingTop="6dp"
android:clipToPadding="false" />
'IT > Android (Kotlin)' 카테고리의 다른 글
Android :: Activity, Fragment 생명주기 (0) | 2022.03.01 |
---|---|
Android :: JetPack - AAC Navigation Component 사용법 (0) | 2022.02.22 |
Android :: Bottom Navigation와 ViewPager 연결 (0) | 2020.06.10 |
Android :: SharedPreferences를 이용한 자동 로그인 기능 (0) | 2020.06.10 |
Android :: startActivityForResult 액티비티 간 데이터 전달 (0) | 2020.06.10 |