코딩ㆍ개발 정보/안드로이드앱 (코틀린)

코틀린 RecyclerView 커스텀 LayoutManager 구성하기

RioRex 2023. 12. 24.

출처: https://mparchive.tistory.com/214

 

수 요소

여기서 여러 메소드 들에서 firstChild 혹은 lastChild를 getChildAt(0)과 getChildAt(childCount -1)로 각각 호출하는 부분이 있는데, 이는 현재 RecyclerView에 실제로 붙어 있는 item들의 맨 첫 아이템, 그리고 가장 마지막 아이템을 참고하는 것임을 주의하자.

 

1. generateDefaultLayoutParams 

RecyclerView의 각 아이템에 적용할 LayoutParams을 지정한다.

override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams = 
   LayoutParams(
      RecyclerView.LayoutParams.MATCH_PARENT,
      RecyclerView.LayoutParams.WRAP_CONTENT
   )

 

2. onLayoutChildren

Recycler에 보여줄 아이템이 1개 이상인 경우 이를 그리도록 호출되는 메소드이다. 

override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) {
   detachAndScrapAttachedViews(recycler)
   if (state.itemCount <= 0) return
   fillBottom(recycler, state.itemCount)
}

 

3. fillBottom

최초 설정된 아이템을 그리거나, 아래로 스크롤하는 경우 아이템을 그리는 메소드.

여기서 childCount는 현재 RecyclerView에 실제로 attach된 아이템의 갯수로, RecyclerView Adapter에 설정한 아이템의 갯수와는 다르다.

private fun fillBottom(recycler: RecyclerView.Recycler, adapterItemCount: Int) {

   var hardTop: Int
   var softTop: Int

   var startPosition: Int

   if (childCount > 0) {
       val lastChild = getChildAt(childCount - 1) ?: return
       val lastChildPosition = getPosition(lastChild)
       startPosition = lastChildPosition + 1
       val lp = lastChild.layoutParams()
       
       // If the item is solid the hard line is moved down to bottom of this view minus allowed overlap
       // If not solid then the hard line is moved down to top of this item
       hardTop =
           if (lp.isSolid) {
               getDecoratedBottom(lastChild) + lp.bottomMargin - ((lastChild.measuredHeight + lp.verticalMargin) * lp.verticalOverlay).toInt()
           } else {
               getDecoratedTop(lastChild)
           }
       // Soft line is always moved to the bottom of given item
       softTop = getDecoratedBottom(lastChild) + lp.bottomMargin
   } else {
       // If there are no attached child views then we start from the top of parent view
       hardTop = parentTop + if (anchorPosition < adapterItemCount) anchorOffset else 0
       softTop = parentTop + if (anchorPosition < adapterItemCount) anchorOffset else 0

       startPosition = if (anchorPosition < adapterItemCount) anchorPosition else 0
   }

   val availableBottom = if (clipToPadding) parentBottom else height

   for (i in startPosition until adapterItemCount) {

       if (hardTop > availableBottom) break

       val view = recycler.getViewForPosition(i)
       addView(view)
       view.setBeelineLayoutParams(i)
       view.measure()
       val lp = view.layoutParams()
       if (lp.isSolid) {
           // For solid items, the top is determined as the lower one of previous item’s hard line
           // or previous item’s soft line minus this view’s vertical overlap allowance
           val top = max(
               hardTop,
               softTop - ((view.measuredHeight + lp.verticalMargin) * lp.verticalOverlay).toInt()
           )
           val bottom = top + view.measuredHeight + lp.verticalMargin
           layoutView(view, top, bottom)
           // The hard line is moved down to bottom of this view minus allowed overlap
           hardTop = bottom - ((view.measuredHeight + lp.verticalMargin) * lp.verticalOverlay).toInt()
           softTop = bottom
       } else {
           // If the item is not solid then we lay it out according to the current hard line
           val top = hardTop
           val bottom = top + view.measuredHeight + lp.verticalMargin
           layoutView(view, top, bottom)
           softTop = bottom
       }
   }
}

 

4. fillTop

위로 스크롤 하는 경우 아래에서 위로 아이템을 그려 나가는 메소드.

출처: https://mparchive.tistory.com/214 [My Program Archive:티스토리]

 

등 ... 출처 참조

반응형

댓글