안드로이드에서는 RecyclerView와 함께 사용 가능한 LayoutManager 라이브러리 3가지를 제공한다. Recycler의 아이템의 배치와 재사용에 대한 정책을 결정하면 LayoutManager의 종류에 따라 아이템의 배치가 변경되며 LayoutManager 라이브러리 종류는 다음과 같다.
📌 LinearLayoutManager를 사용하여 세로 정렬
binding.recyclerView.layoutManager = LinearLayoutManager(this)
💡 자세한 내용은 RecyclerView 세로 정렬 이전 포스팅을 확인해보자
📌 LinearLayoutManager를 사용하여 가로 정렬
binding.recyclerview.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
💡 두 번째 인자는 레이아웃 방향(HORIZONTAL 또는 VERTICAL)을 의미하며 세 번째 인자는 reverseLayout을 의미한다. reverseLayout을을 true로 설정 시 레이아웃이 끝에서 시작된다.
// activity_recycler_view.xml
<?xml version="1.0" encoding="utf-8"?>
<layout>
<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"
tools:context=".recyclerview.RecyclerViewActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</layout>
// RecyclerModel.kt
class RecyclerModel(
val image: Int, val title: String, val content: String, val price: String
)
// item_rv_horizontal.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/imageArea"
android:layout_width="150dp"
android:layout_height="150dp" />
<TextView
android:id="@+id/titleArea"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="2"
android:textColor="@color/black"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="@+id/contentArea"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="1"
android:textColor="@color/black"
android:textSize="12sp" />
<TextView
android:id="@+id/priceArea"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="1"
android:textColor="@color/black"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
// RecyclerHorizontalAdapter.kt
class RecyclerHorizontalAdapter(val items: MutableList<RecyclerModel>) :
RecyclerView.Adapter<RecyclerHorizontalAdapter.ViewHolder>() {
interface onItemClickListener {
fun onItemClick(position: Int)
}
private lateinit var itemClickListener: onItemClickListener
fun setItemClickListener(itemClickListener: onItemClickListener) {
this.itemClickListener = itemClickListener
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): RecyclerHorizontalAdapter.ViewHolder {
val v =
LayoutInflater.from(parent.context).inflate(R.layout.item_rv_horizontal, parent, false)
return ViewHolder(v)
}
override fun onBindViewHolder(holder: RecyclerHorizontalAdapter.ViewHolder, position: Int) {
holder.itemView.setOnClickListener {
itemClickListener.onItemClick(position)
}
holder.bindItems(items[position])
}
override fun getItemCount(): Int {
return items.count()
}
inner class ViewHolder(itemView: View) :
RecyclerView.ViewHolder(itemView) {
fun bindItems(items: RecyclerModel) {
val imageArea = itemView.findViewById<ImageView>(R.id.imageArea)
val titleArea = itemView.findViewById<TextView>(R.id.titleArea)
val contentArea = itemView.findViewById<TextView>(R.id.contentArea)
val priceArea = itemView.findViewById<TextView>(R.id.priceArea)
imageArea.setImageResource(items.image)
titleArea.text = items.title
contentArea.text = items.content
priceArea.text = items.price
}
}
}
class RecyclerViewActivity : AppCompatActivity() {
lateinit var binding: ActivityRecyclerViewBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_recycler_view)
initRecycler()
}
private fun initRecycler() {
val itemList = mutableListOf<RecyclerModel>()
itemList.add(RecyclerModel(R.drawable.item_lv_01, "마리떼 프랑소와 저버", "CLASSIC LOGO CAP beige", "49,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_02, "마리떼 프랑소와 저버", "CLASSIC LOGO WOOL ECO BAG blue", "49,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_03, "마리떼 프랑소와 저버", "COLOR BLOCK SATIN SCRUNCHIE navy", "39,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_04, "마리떼 프랑소와 저버", "CLASSIC LOGO BACKPACK light blue", "159,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_05, "마리떼 프랑소와 저버", "CLASSIC LOGO COLOR BEANIE navy", "49,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_06, "원브릴리언트", "Ivan-OB166-Black", "112,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_07, "시엔느", "Washing Lettering Ball Cap (Navy)", "49,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_08, "마뗑킴", "ACCORDION WALLET IN WHITE", "88,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_09, "마리떼 프랑소와 저버", "CIRCLE LOGO SATIN HAIRBAND ivorye", "29,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_10, "리엔느와르","Dot Toggle Pearl Necklace (2color)", "57,000원"))
val adapter = RecyclerHorizontalAdapter(itemList)
binding.recyclerview.adapter = adapter
binding.recyclerview.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
adapter.setItemClickListener(object: RecyclerHorizontalAdapter.onItemClickListener{
override fun onItemClick(position: Int) {
Toast.makeText(applicationContext, "RecyclerView: ${itemList[position].title}", Toast.LENGTH_SHORT).show()
}
})
}
}
📌 GridLayoutManager를 사용하여 수직 격자 정렬
binding.recyclerview.layoutManager = GridLayoutManager(this, 2)
💡 수직 GridLayoutManager를 생성하며 두 번째 인자는 열의 개수를 의미한다.
❗️ RecyclerView의 아이템과 Activity 부분만 수정하였으며 그 외는 위에서 사용한 코드를 그대로 사용하였다.
// item_rv_horizontal.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/imageArea"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true" />
<TextView
android:id="@+id/titleArea"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="2"
android:textColor="@color/black"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="@+id/contentArea"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="1"
android:textColor="@color/black"
android:textSize="12sp" />
<TextView
android:id="@+id/priceArea"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="1"
android:textColor="@color/black"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
// RecyclerViewActivity.kt
class RecyclerViewActivity : AppCompatActivity() {
lateinit var binding: ActivityRecyclerViewBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_recycler_view)
initRecycler()
}
private fun initRecycler() {
val itemList = mutableListOf<RecyclerModel>()
itemList.add(RecyclerModel(R.drawable.item_lv_01, "마리떼 프랑소와 저버", "CLASSIC LOGO CAP beige", "49,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_02, "마리떼 프랑소와 저버", "CLASSIC LOGO WOOL ECO BAG blue", "49,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_03, "마리떼 프랑소와 저버", "COLOR BLOCK SATIN SCRUNCHIE navy", "39,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_04, "마리떼 프랑소와 저버", "CLASSIC LOGO BACKPACK light blue", "159,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_05, "마리떼 프랑소와 저버", "CLASSIC LOGO COLOR BEANIE navy", "49,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_06, "원브릴리언트", "Ivan-OB166-Black", "112,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_07, "시엔느", "Washing Lettering Ball Cap (Navy)", "49,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_08, "마뗑킴", "ACCORDION WALLET IN WHITE", "88,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_09, "마리떼 프랑소와 저버", "CIRCLE LOGO SATIN HAIRBAND ivorye", "29,000원"))
itemList.add(RecyclerModel(R.drawable.item_lv_10, "리엔느와르","Dot Toggle Pearl Necklace (2color)", "57,000원"))
val adapter = RecyclerHorizontalAdapter(itemList)
binding.recyclerview.adapter = adapter
binding.recyclerview.layoutManager = GridLayoutManager(this, 2)
adapter.setItemClickListener(object: RecyclerHorizontalAdapter.onItemClickListener{
override fun onItemClick(position: Int) {
Toast.makeText(applicationContext, "RecyclerView: ${itemList[position].title}", Toast.LENGTH_SHORT).show()
}
})
}
}