Android

Grid 격자 테두리 그리기(onDraw in RecyclerView.ItemDecoration)

그란. 2021. 7. 4. 15:30

 

RecyclerView.ItemDecoration 에서 onDraw 를 이용하여 직접 아이템에 대해 그리는 방법

 

 

아래와 같은 GridLayout 을 만들려고 한다.

고려해야할점

  • 각 아이템 항목마다 회색 Stroke
  • 맨왼쪽 아이템은 왼쪽에 뚫려져 있음 + 맨 오른쪽 아이템은 오른쪽이 뚫려져 있음
  • 단순히 하나의 아이템 레이아웃에 사각형의 Stroke를 background로 지정하면 중간선들이 겹쳐보이는 현상이 있음 
    • Stroke만큼의 padding 을 줘야함
    • RecyclerViewAdapter의 onBindViewHolder에서 맨 왼쪽과 맨 오른쪽인 경우 View를 숨겨야함

 

cf) 숨기는 코드 Sample 

 override fun onBindViewHolder(holder: BaseViewHolder<CommentUiModel>, position: Int) {
        super.onBindViewHolder(holder, position)
        if (getItem(position) is CommentUiModel.Sub && getItem(position + 1) is CommentUiModel.Base) {
            DataBindingUtil.bind<ItemPostNestedReplyBinding>(holder.itemView)?.apply {
                viewBottom.visibility = View.VISIBLE
            }
        }
        if (getItem(position) is CommentUiModel.Base && getItem(position + 1) is CommentUiModel.Sub) {
            DataBindingUtil.bind<ItemPostReplyBinding>(holder.itemView)?.apply {
                viewBottom.visibility = View.INVISIBLE
            }
        }
    }

 

 

-> View를 숨겨야하는 경우 때문에 background로 지정하는것을 포기하고 네모 선들을 각각 View로써 만들어야하는.. 

( 까다로운 작업이 될것같다.. 더쉬운 방법을 찾아보자) 

 

 

어떻게 그릴것인가?

 

1. 각 아이템들에 대해 하단 라인을 먼저 그린다 ( 모든 아이템들이 가지고있는 공통 요소)

 

2. 맨 오른쪽에 있지 않은 아이템들은 오른쪽 라인을 그린다

 

3. 맨 위쪽에 있는 아이템들에 대해 위쪽 라인을 그린다 

 

private class GridGuidelineDecoration(
        strokeWidth: Int,
        @ColorRes
        private val lineColorResId: Int
    ) : RecyclerView.ItemDecoration() {
        private val pxStrokeWidth: Float = strokeWidth.pxFromDp

        override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
            val spanCount = (parent.layoutManager as GridLayoutManager).spanCount
            val paint = Paint().apply {
                this.isAntiAlias = true
                this.color = ContextCompat.getColor(parent.context, lineColorResId)
                this.strokeWidth = pxStrokeWidth
                this.style = Paint.Style.STROKE
            }
            parent.children.forEach { itemView ->
                val position = parent.getChildAdapterPosition(itemView)
                val spanIndex = (itemView.layoutParams as GridLayoutManager.LayoutParams).spanIndex
                val lineIndex = position / spanCount


	// 1. 각 아이템들에 대해 하단 라인을 먼저 그린다 ( 모든 아이템들이 가지고있는 공통 요소)

                c.drawLine(
                    itemView.left.toFloat(),
                    itemView.bottom.toFloat(),
                    itemView.right.toFloat(),
                    itemView.bottom.toFloat(),
                    paint
                )
                
                

	// 2. 맨 오른쪽에 있지 않은 아이템들은 오른쪽 라인을 그린다

                if (spanIndex != spanCount - 1) {
                    c.drawLine(
                        itemView.right.toFloat(),
                        itemView.top.toFloat(),
                        itemView.right.toFloat(),
                        itemView.bottom.toFloat(),
                        paint
                    )
                }


	// 3. 맨 위쪽에 있는 아이템들에 대해 위쪽 라인을 그린다 
                if (lineIndex == 0) {
                    c.drawLine(
                        itemView.left.toFloat(),
                        itemView.top.toFloat(),
                        itemView.right.toFloat(),
                        itemView.top.toFloat(),
                        paint
                    )
                }

            }
        }
    }