-
반응형
Android 개발자라면 ListView나 RecyclerView를 한번쯤은 사용 해봤을 것입니다.
어플뿐만 아니라 수많은 곳에서 쓰이고 있지요.그 중 RecyclerView에서 Multiple View Type을 한번 구현해보겠습니다.
RecyclerView는 수많은 곳에서 사용되고 있습니다. 그리고 여러 타입을 가지고 있지요.
하다못해 아래와 같이 우리가 자주 사용하는 카카오톡에서도
이미지를 보낼 때, 텍스트를 보낼 때, 이모티콘을 보낼 때 등 여러 뷰 타입을 사용하지요.(사실 카카오톡에서 RecyclerView를 사용하는 지는 모르겠습니다. 다만 RecyclerView로도 동일하게 구현해 낼 수 있습니다.)
ListView에서는 뷰홀더 패턴이 권장되었습니다.
뷰홀더 패턴을 사용하지 않을땐 무언갈 수정할 때마다 부르는 findViewById()가 리스트 뷰의 지연을 초래했지요.
하지만 뷰홀더 패턴을 적용하며 리스트 뷰의 속도는 빨라졌습니다.RecyclerView에도 뷰홀더 패턴이 있습니다. 리사이클러뷰에는 뷰홀더 패턴이 강제된다는 것이 리스트뷰와의 차이점입니다.
이전의 리스트뷰는 선택적이였지만 성능 차이가 워낙 커서 변화된 것으로 생각됩니다.또한 recyclerView는 수평 스크롤, 격자형 리스트 등 다양한 커스텀 기능을 지원합니다. RecyclerView.LayoutManager란 클래스를 사용해 간단히 만들 수 있습니다.
구성은 RecyclerView, Adapter, Data Class, LayoutManager 등등으로 이루어집니다.
먼저 위와 같이 간단한 두 가지 타입의 뷰를 RecyclerView에 배치하여 보겠습니다.
RecyclerAdapter.kt
class RecyclerAdapter(val context: Context, val boardList: MutableList<DataClass>): RecyclerView.Adapter<RecyclerAdapter.BaseViewHolder<*>>() { val TYPE_1 = 0 val TYPE_2 = 1 abstract class BaseViewHolder<T>(itemView: View) : RecyclerView.ViewHolder(itemView) { abstract fun bind(item: T) } inner class ViewHolder1(itemView:View):BaseViewHolder<DataClass>(itemView){ val text = itemView.form_recycler_1_text val btn = itemView.form_recycler_1_btn override fun bind(item: DataClass) { text?.text = item.string btn.setOnClickListener { Toast.makeText(context,"1번 타입", Toast.LENGTH_SHORT).show() } } } inner class ViewHolder2(itemView: View):BaseViewHolder<DataClass>(itemView){ val text = itemView.form_recycler_2_text val btn = itemView.form_recycler_2_btn override fun bind(item: DataClass) { text?.text = item.string btn.setOnClickListener { Toast.makeText(context,"2번 타입", Toast.LENGTH_SHORT).show() } } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> { return when(viewType){ TYPE_1 -> { val view = LayoutInflater.from(context).inflate(R.layout.form_recyclerview_1, parent, false) ViewHolder1(view) } TYPE_2 -> { val view = LayoutInflater.from(context).inflate(R.layout.form_recyclerview_2, parent, false) ViewHolder2(view) } else -> throw IllegalArgumentException("Invalid view type") } } override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) { val element = boardList[position] when(holder){ is ViewHolder1 -> holder.bind(element as DataClass) is ViewHolder2 -> holder.bind(element as DataClass) else -> throw IllegalArgumentException() } } override fun getItemViewType(position: Int): Int { return boardList[position].type } override fun getItemCount(): Int { return boardList.size } }
RecyclerView.Adapter 를 상속받았으며 getItemViewType을 오버라이딩해 onCreateViewHolder에서 viewType에 따라 다른 레이아웃을 inflate 해주고 ViewHolder로 바인딩 하는 Adapter입니다.
-
getItemViewType : 뷰의 타입을 return합니다. 위에서는 MutableList<DataClass>의 type을 return 해주었습니다.
-
onCreateViewHolder : 뷰 홀더를 생성하고 뷰를 붙여주는 기능을 합니다.
-
onBindViewHolder : 재활용되는 뷰가 호출하여 실행되는 메소드이며 뷰홀더를 전달하고 position의 데이터를 결합시킵니다.
-
ViewHolder : 뷰의 자식 뷰들을 매핑하고 데이터 바인딩해주는 기능을 합니다.
-
getItemCount : RecyclerView의 아이템 수를 리턴합니다.
type 에 따라 위에서 보인 두 가지 레이아웃인 form_recyclerview_1와 form_recyclerview_2를 나누어 사용한 예제입니다.
MainActivity.kt
class MainActivity : AppCompatActivity() { val TYPE_1 = 0 val TYPE_2 = 1 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) var dataList:MutableList<DataClass> = mutableListOf() dataList.add(DataClass("1번타입_1", TYPE_1)) dataList.add(DataClass("1번타입_2", TYPE_1)) dataList.add(DataClass("2번타입_1", TYPE_2)) dataList.add(DataClass("2번타입_2", TYPE_2)) var recyclerAdapter = RecyclerAdapter(this, dataList) main_recyclerVIew.adapter = recyclerAdapter main_recyclerVIew.layoutManager = LinearLayoutManager(this) //두번째 인자값으로 LinearLayoutManager.HORIZONTAL 을 주면 수평 리스트가 됩니다. //세번째 인자값으로 true를 줄 경우 리스트의 순서가 reverse 됩니다. //main_recyclerVIew.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false) //(두번째 인자값 = 격자형 리스트의 열 수) 입니다. //main_recyclerVIew.layoutManager = GridLayoutManager(this, 3) //(첫번째 인자값 = 격자형 리스트의 열 수) 입니다. //main_recyclerVIew.layoutManager = StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL) } }
앞서 RecyclerView는 LayoutManager를 이용해 수직스크롤, 수평스크롤, 격자형 등 여러 가지 형태로 나타낼 수 있다고 말씀드렸죠? LayoutManager 3가지 종류를 소개합니다.
-
수평/수직 리스트 ( LinearLayoutManager 사용 ) : 수평, 수직 스크롤을 제공해줍니다.
-
Grid List ( GridLayoutManager 사용 ) : 사진첩 같은 격자형 리스트를 만들 수 있습니다.
-
Staggered Grid List ( StaggeredGridLayoutManager 사용) : 뷰마다 크기가 다른 격자형 리스트를 만들 수 있습니다.
그림으로 설명하면 이런 느낌입니다.
어떤 차이인지 아시겠나요?
GridLayoutManager를 사용할 경우 같은 행에서 가장 height가 큰 뷰를 중심으로 height가 설정됩니다.
반면 StaggeredGridLayoutManager를 사용할 경우 제한이 없죠.
실행결과
form_recyclerview_1, form_recyclerview_2의 최상단 layout의 weight, height가 모두 wrap_content인 채로 구현한 예제입니다.
원하시는 조건에 맞춰 xml의 최상단 view의 크기를 조절하시면 될듯 합니다.
반응형'개발 끄적끄적 > Android' 카테고리의 다른 글
[Android Kotlin] 갤러리에서 이미지 가져와 RecyclerView에 적용하기 (0) 2020.06.03 [Android Kotlin] Permission(권한) 얻기 (0) 2020.06.02 [Android Kotlin] Navigation Drawer를 이용한 사이드 메뉴 만들기 (0) 2020.06.01 [Android Studio] 초보 개발자 로그캣(LogCat) 확인 방법 - 에러 찾는 방법 (0) 2020.05.30 [JAVA] 오라클 JDBC 연결, insert문 실행해보기 (0) 2020.05.30 -